import {Controller} from '@hotwired/stimulus';

/**
 * Always-on navigation preference restorer.
 *
 * Re-injects the admin's stored list preferences — selected edition/role
 * path-slug, view, sort, and sidebar filters — into Turbo navigations whose
 * destination is a known list prefix. This is what makes the main nav and the
 * breadcrumbs "remember" the active selection: a click on the bare
 * `/admin/angebote` becomes `/admin/angebote/sommer+oster`.
 *
 * The *capturing* half lives in controllers/list.js — it owns each list's
 * viewKey, path prefix, and Live component, and writes the localStorage
 * buckets. This controller only READS those buckets, so it can (and must) run
 * on EVERY admin page, including detail/edit/show pages that mount no list.
 * Previously the rewriter lived in list.js too, so it was only active while a
 * list page was on screen — navigating away from an offer detail page forgot
 * the selection. Mounted globally on <body>, it now works from anywhere.
 *
 * DOM contract: data-controller="ferienpass--admin-nav-restore" on <body>.
 */
export default class extends Controller {
    // URL params mirrored to localStorage per list, each in its own namespace.
    // Must stay in sync with the same list in controllers/list.js (the writer).
    static PARAMS = [
        { name: 'view', storagePrefix: 'admin-view-prefered' },
        { name: 'sort', storagePrefix: 'admin-sort-prefered' },
    ];

    connect() {
        this.onBeforeVisit = this.onBeforeVisit.bind(this);
        document.addEventListener('turbo:before-visit', this.onBeforeVisit);
    }

    disconnect() {
        document.removeEventListener('turbo:before-visit', this.onBeforeVisit);
    }

    _readRoutes() {
        try {
            const raw = localStorage.getItem('admin-view-prefered--routes');
            const parsed = raw ? JSON.parse(raw) : null;
            return (parsed && typeof parsed === 'object') ? parsed : {};
        } catch (_) {
            return {};
        }
    }

    /** Inject any stored params into the destination URL when it lands in a
     *  known list's prefix and doesn't already pin those params. */
    onBeforeVisit(event) {
        let target;
        try {
            target = new URL(event.detail.url, window.location.href);
        } catch (_) {
            return;
        }

        // Longest-prefix wins so a nested list (if any) takes precedence.
        let matchedKey = null;
        let matchedPrefix = null;
        let matchedLen = 0;
        for (const [viewKey, prefix] of Object.entries(this._readRoutes())) {
            if (typeof prefix !== 'string') continue;
            if (target.pathname.startsWith(prefix) && prefix.length > matchedLen) {
                matchedKey = viewKey;
                matchedPrefix = prefix;
                matchedLen = prefix.length;
            }
        }
        if (!matchedKey) return;

        let rewritten = false;

        // Path-slug injection — only when the destination is the BARE list
        // prefix (e.g. a navbar/breadcrumb link to /admin/angebote). Any path
        // tail — even an edition slug from the EditionSwitcher — is the user's
        // explicit choice and wins outright. We compare with trailing slashes
        // normalized away on both sides.
        const targetPath = target.pathname.replace(/\/+$/, '');
        const bare = matchedPrefix.replace(/\/+$/, '');
        if (targetPath === bare) {
            let storedSlug;
            try {
                storedSlug = localStorage.getItem(`admin-path-prefered--${matchedKey}`);
            } catch (_) {
                storedSlug = null;
            }
            if (storedSlug) {
                target.pathname = `${bare}/${storedSlug}`;
                rewritten = true;
            }
        }

        for (const { name, storagePrefix } of this.constructor.PARAMS) {
            if (target.searchParams.has(name)) continue; // explicit deep-link wins
            let stored;
            try {
                stored = localStorage.getItem(`${storagePrefix}--${matchedKey}`);
            } catch (_) {
                continue;
            }
            if (stored === null || stored === '') continue;
            target.searchParams.set(name, stored);
            rewritten = true;
        }

        // Filter sidebar (multi-key). Only inject when the target has NO
        // filter[*] params already — partial overrides would confuse the
        // sidebar (mixing user's deep-link filters with stored ones).
        const hasAnyFilter = [...target.searchParams.keys()].some(k => k.startsWith('filter['));
        if (!hasAnyFilter) {
            let storedFilters = null;
            try {
                const raw = localStorage.getItem(`admin-filter-prefered--${matchedKey}`);
                storedFilters = raw ? JSON.parse(raw) : null;
            } catch (_) {}
            if (storedFilters && typeof storedFilters === 'object') {
                for (const [k, v] of Object.entries(storedFilters)) {
                    if (v === null || v === '') continue;
                    target.searchParams.set(`filter[${k}]`, String(v));
                    rewritten = true;
                }
            }
        }

        if (!rewritten) return;
        const newUrl = target.toString();
        if (newUrl === event.detail.url) return;

        event.preventDefault();
        setTimeout(() => window.Turbo.visit(newUrl), 0);
    }
}
