import { usePage } from '@inertiajs/vue3';
import {
    Activity,
    Archive,
    ArrowLeftRight,
    BadgeCheck,
    Bell,
    BookOpen,
    Box,
    Boxes,
    ChartNoAxesColumn,
    Clock,
    Cloud,
    Coins,
    CreditCard,
    Download,
    FileText,
    Fingerprint,
    Flag,
    Globe,
    HardDrive,
    Landmark,
    LayoutGrid,
    LayoutTemplate,
    Layers,
    LifeBuoy,
    ListTodo,
    Mail,
    Inbox,
    Key,
    KeyRound,
    MessageSquare,
    Package,
    Palette,
    Percent,
    Puzzle,
    Radio,
    Receipt,
    RefreshCw,
    Server,
    Settings,
    Shield,
    ShoppingCart,
    SlidersHorizontal,
    Sparkles,
    Timer,
    TrendingUp,
    UserRound,
    Users,
    Zap,
} from '@lucide/vue';
import { computed } from 'vue';
import type { Component, ComputedRef } from 'vue';
import { toUrl } from '@/lib/utils';
import { dashboard } from '@/routes';
import { can } from '@admin-theme/lib/can';

export type SidebarItem = {
    id: string;
    title: string;
    href: string;
    icon: Component;
    /** URLs qui activent cet item (une seule, sauf item synthétique). */
    paths: string[];
    /** Sous-pages d’un hub `registerModule` / `registerHub`. */
    children: SidebarItem[];
};

export type SidebarGroup = {
    id: string;
    label: string;
    items: SidebarItem[];
};

export type OpsDomain = {
    id: string;
    label: string;
    icon: Component;
    items: SidebarItem[];
};

export type NavDestination = {
    id: string;
    title: string;
    href: string;
    icon: Component;
    group: string;
    kind: 'ops' | 'config';
};

export type ConfigPage = {
    id: string;
    title: string;
    href: string;
    icon: Component;
    hiddenFromHub?: boolean;
    cluster?: string | null;
};

export type ConfigSection = {
    id: string;
    label: string;
    pages: ConfigPage[];
    icon: Component;
    blurb: string;
};

export type NavHubPage = {
    id: string;
    title: string;
    href: string;
    icon: Component;
    active: boolean;
};

export type ActiveHub = {
    id: string;
    title: string;
    href: string;
    icon: Component;
    groupLabel: string;
    pages: NavHubPage[];
};

type RawNavPage = {
    id?: string;
    title: string;
    href: string;
    icon?: string;
    permission?: string | null;
};

type RawNavItem = {
    id?: string;
    title: string;
    href: string;
    icon?: string;
    group?: string;
    section?: string;
    hidden_from_hub?: boolean;
    pages?: RawNavPage[];
};

const groupLabels: Record<string, string> = {
    console: 'Console',
    general: 'Général',
    comptes: 'Comptes',
    catalogue: 'Catalogue',
    domaines: 'Domaines',
    infrastructure: 'Infrastructure',
    facturation: 'Facturation',
    insights: 'Insights',
    support: 'Support',
    acces: 'Accès',
    systeme: 'Système',
    addons: 'Modules',
    modules: 'Modules',
};

const iconMap: Record<string, Component> = {
    Activity,
    Archive,
    ArrowLeftRight,
    Bell,
    BookOpen,
    Box,
    Boxes,
    ChartNoAxesColumn,
    Clock,
    Cloud,
    Coins,
    CreditCard,
    Download,
    FileText,
    Fingerprint,
    Flag,
    Globe,
    HardDrive,
    Key,
    KeyRound,
    Landmark,
    LayoutTemplate,
    Layers,
    LifeBuoy,
    ListTodo,
    Mail,
    Inbox,
    MessageSquare,
    Package,
    Percent,
    Puzzle,
    Radio,
    Receipt,
    RefreshCw,
    Server,
    Settings,
    Shield,
    ShoppingCart,
    SlidersHorizontal,
    Sparkles,
    Timer,
    TrendingUp,
    UserRound,
    Users,
    Zap,
};

function resolveIcon(name: string | undefined, fallback: Component): Component {
    return iconMap[name ?? ''] ?? fallback;
}

/** Ordre d'affichage des domaines de l'espace Configuration. */
const configSectionOrder = [
    'general',
    'catalogue',
    'facturation',
    'insights',
    'domaines',
    'support',
    'acces',
    'systeme',
];

const configSectionMeta: Record<string, { icon: Component; blurb: string }> = {
    general: {
        icon: Settings,
        blurb: 'Plateforme, marque, thèmes et champs de compte.',
    },
    catalogue: {
        icon: Package,
        blurb: 'Produits, options et tunnel de commande.',
    },
    facturation: {
        icon: Receipt,
        blurb: 'Numérotation, taxes, devises et paiements.',
    },
    insights: {
        icon: ChartNoAxesColumn,
        blurb: 'Définition du MRR et des indicateurs.',
    },
    domaines: {
        icon: Globe,
        blurb: 'Registrars, extensions et renouvellement.',
    },
    support: {
        icon: LifeBuoy,
        blurb: 'Tickets, SLA et automatisations.',
    },
    acces: {
        icon: Shield,
        blurb: 'Sécurité, agents et clés d’API.',
    },
    systeme: {
        icon: Server,
        blurb: 'E-mail, modules et santé de l’installation.',
    },
};

function sectionMeta(groupId: string): { icon: Component; blurb: string } {
    return (
        configSectionMeta[groupId] ?? {
            icon: Settings,
            blurb: '',
        }
    );
}

/** Ordre des lignes dans un domaine (ids inconnus à la fin). */
const configPageOrder: Record<string, string[]> = {
    general: [
        'core-platform',
        'core-storefronts',
        'core-themes',
        'core-appearance',
        'account-fields',
    ],
    catalogue: [
        'catalog-products',
        'catalog-groups',
        'catalog-options',
        'catalog-order-form',
        'provisioning-connections',
        'licensing-settings',
    ],
    facturation: [
        'billing-settings',
        'billing-gateways',
        'billing-taxes',
        'billing-currencies',
        'billing-promos',
    ],
    insights: ['insights-settings'],
    domaines: [
        'domains-settings',
        'domains-registrars',
        'domains-tlds',
        'domains-tld-import',
    ],
    support: [
        'support-settings',
        'support-hours',
        'support-sla',
        'support-departments',
        'support-statuses',
        'support-urgency',
        'support-replies',
        'support-macros',
        'support-escalations',
    ],
    acces: [
        'core-security',
        'core-two-factor',
        'staff-agents',
        'staff-roles',
        'staff-api-credentials',
        'oauth-apps',
    ],
    systeme: [
        'core-mail',
        'email-templates',
        'email-log',
        'core-storage',
        'core-modules',
        'core-updates',
        'automation',
        'system-imports',
        'system-health',
    ],
};

const configPageClusters: Record<string, string> = {
    'support-settings': 'Politique',
    'support-hours': 'Politique',
    'support-sla': 'Politique',
    'support-departments': 'Cycle de vie',
    'support-statuses': 'Cycle de vie',
    'support-urgency': 'Cycle de vie',
    'support-replies': 'Automatisations',
    'support-macros': 'Automatisations',
    'support-escalations': 'Automatisations',
    'core-mail': 'E-mail',
    'email-templates': 'E-mail',
    'email-log': 'E-mail',
    'core-storage': 'Fichiers',
    'core-modules': 'Plateforme',
    'core-updates': 'Plateforme',
    automation: 'Plateforme',
    'system-health': 'Plateforme',
};

function sortConfigPages(sectionId: string, pages: ConfigPage[]): ConfigPage[] {
    const order = configPageOrder[sectionId];

    if (!order) {
        return pages;
    }

    return [...pages].sort((a, b) => {
        const ai = order.indexOf(a.id);
        const bi = order.indexOf(b.id);

        return (ai === -1 ? 1000 : ai) - (bi === -1 ? 1000 : bi);
    });
}

function decorateConfigPage(page: ConfigPage): ConfigPage {
    return {
        ...page,
        cluster: configPageClusters[page.id] ?? null,
    };
}

export const CONFIG_HUB_PATH = '/admin/configuration';

function pathOf(href: Parameters<typeof toUrl>[0]): string {
    const url = toUrl(href);

    if (!url.startsWith('http')) {
        return url;
    }

    try {
        return new URL(url).pathname;
    } catch {
        return url;
    }
}

function matches(currentPath: string, path: string): boolean {
    // La racine « /admin » ne matche qu'en égalité stricte,
    // sinon elle capterait toutes les pages.
    if (path === '/admin') {
        return currentPath === path;
    }

    return currentPath === path || currentPath.startsWith(`${path}/`);
}

export type UseAdminNavReturn = {
    groups: ComputedRef<SidebarGroup[]>;
    pins: ComputedRef<SidebarItem[]>;
    domains: ComputedRef<OpsDomain[]>;
    destinations: ComputedRef<NavDestination[]>;
    activeItemId: ComputedRef<string | null>;
    activeDomainId: ComputedRef<string | null>;
    configSections: ComputedRef<ConfigSection[]>;
    configActive: ComputedRef<boolean>;
    onConfigHub: ComputedRef<boolean>;
    activeConfigId: ComputedRef<string | null>;
    activeConfigSection: ComputedRef<ConfigSection | null>;
    activeHub: ComputedRef<ActiveHub | null>;
    moduleConsoles: ComputedRef<SidebarItem[]>;
};

const opsDomainIcons: Record<string, Component> = {
    catalogue: Package,
    domaines: Globe,
    facturation: Receipt,
    insights: ChartNoAxesColumn,
    support: LifeBuoy,
    infrastructure: Server,
    systeme: Server,
    modules: Puzzle,
};

export function normalizeSearch(value: string): string {
    return value
        .normalize('NFD')
        .replace(/[\u0300-\u036f]/g, '')
        .toLowerCase();
}

export function isFlatDomain(domain: OpsDomain): boolean {
    return domain.items.length === 1 && domain.items[0].children.length === 0;
}

export function matchDestination(
    destination: NavDestination,
    needle: string,
): boolean {
    if (needle === '') {
        return false;
    }

    return (
        normalizeSearch(destination.title).includes(needle) ||
        normalizeSearch(destination.group).includes(needle)
    );
}

const sidebarGroupOrder = [
    'catalogue',
    'domaines',
    'facturation',
    'insights',
    'support',
    'infrastructure',
    'systeme',
    'modules',
];

function navGroupId(group: string | undefined): string {
    const id = group ?? 'modules';

    return id === 'addons' ? 'modules' : id;
}

function sidebarItemFromRaw(item: RawNavItem): SidebarItem {
    const href = pathOf(item.href);
    const hubIcon = resolveIcon(item.icon, Box);
    const children = (item.pages ?? []).map((hubPage) => {
        const pageHref = pathOf(hubPage.href);

        return {
            id: hubPage.id ?? pageHref,
            title: hubPage.title,
            href: pageHref,
            icon: resolveIcon(hubPage.icon, hubIcon),
            paths: [pageHref],
            children: [],
        };
    });

    return {
        id: item.id ?? href,
        title: item.title,
        href,
        icon: hubIcon,
        paths: [...new Set([href, ...children.map((child) => child.href)])],
        children,
    };
}

export function useAdminNav(): UseAdminNavReturn {
    const page = usePage();

    const rawNav = computed(
        (): RawNavItem[] =>
            (page.props.platform as { nav?: RawNavItem[] })?.nav ?? [],
    );

    /*
     * Premier niveau : tableau de bord, comptes, commandes (group: console),
     * utilisateurs. Commandes est une destination quotidienne, pas une
     * sous-page Facturation.
     */
    const consoleGroup = computed((): SidebarGroup => {
        const extras = rawNav.value
            .filter(
                (item) =>
                    item.section !== 'config' &&
                    navGroupId(item.group) === 'console',
            )
            .map(sidebarItemFromRaw);

        const pin = (
            id: string,
            title: string,
            href: string,
            icon: Component,
        ): SidebarItem => ({
            id,
            title,
            href,
            icon,
            paths: [href],
            children: [],
        });

        return {
            id: 'console',
            label: groupLabels.console,
            items: [
                pin(
                    'core-dashboard',
                    'Tableau de bord',
                    pathOf(dashboard()),
                    LayoutGrid,
                ),
                ...(can('accounts.view')
                    ? [
                          pin(
                              'core-accounts',
                              'Comptes',
                              '/admin/accounts',
                              Users,
                          ),
                      ]
                    : []),
                ...extras,
                ...(can('users.view')
                    ? [
                          pin(
                              'core-users',
                              'Utilisateurs',
                              '/admin/users',
                              UserRound,
                          ),
                      ]
                    : []),
            ],
        };
    });

    /*
     * Pages de configuration du cœur (hors modules) : identité de marque,
     * thèmes et plomberie système. Les modules ajoutent les leurs via
     * NavRegistry::registerConfig.
     */
    const coreConfigPages = computed(
        (): Array<ConfigPage & { group: string }> => {
            const theme = page.props.theme as
                | {
                      client?: string | null;
                      configPages?: Array<{ id: string; title: string }>;
                  }
                | undefined;
            const config = theme?.configPages?.[0];
            const appearanceHref =
                theme?.client && config
                    ? `/admin/themes/${theme.client}/configure/${config.id}`
                    : '/admin/appearance';

            return [
                {
                    id: 'core-platform',
                    title: 'Plateforme',
                    href: '/admin/platform',
                    icon: Settings,
                    group: 'general',
                    permission: 'system.settings.manage',
                },
                {
                    id: 'core-storefronts',
                    title: 'Marque',
                    href: '/admin/storefronts',
                    icon: BadgeCheck,
                    group: 'general',
                    permission: 'branding.update',
                },
                {
                    id: 'core-appearance',
                    title: 'Apparence',
                    href: appearanceHref,
                    icon: Palette,
                    group: 'general',
                    permission: 'branding.update',
                    hiddenFromHub: true,
                },
                {
                    id: 'core-themes',
                    title: 'Thèmes',
                    href: '/admin/themes',
                    icon: Layers,
                    group: 'general',
                    permission: 'themes.manage',
                },
                {
                    id: 'core-modules',
                    title: 'Modules',
                    href: '/admin/modules',
                    icon: Boxes,
                    group: 'systeme',
                    permission: 'modules.manage',
                },
                {
                    id: 'core-updates',
                    title: 'Mises à jour',
                    href: '/admin/updates',
                    icon: RefreshCw,
                    group: 'systeme',
                    permission: 'updates.view',
                },
            ].filter((item) => !item.permission || can(item.permission));
        },
    );

    /*
     * Espace Configuration : sections ordonnées (Général, Catalogue, …),
     * fusion des pages cœur et des items modules `section: 'config'`.
     * Les groupes inconnus (modules tiers) sont ajoutés en fin de liste.
     */
    const configSections = computed((): ConfigSection[] => {
        const raw = (page.props.platform as { nav?: RawNavItem[] })?.nav ?? [];

        const byId = new Map<string, ConfigSection>();
        const ordered: ConfigSection[] = [];

        const sectionFor = (groupId: string): ConfigSection => {
            let section = byId.get(groupId);

            if (!section) {
                const meta = sectionMeta(groupId);

                section = {
                    id: groupId,
                    label: groupLabels[groupId] ?? groupId,
                    pages: [],
                    icon: meta.icon,
                    blurb: meta.blurb,
                };
                byId.set(groupId, section);
                ordered.push(section);
            }

            return section;
        };

        for (const groupId of configSectionOrder) {
            sectionFor(groupId);
        }

        for (const item of coreConfigPages.value) {
            sectionFor(item.group).pages.push(
                decorateConfigPage({
                    id: item.id,
                    title: item.title,
                    href: item.href,
                    icon: item.icon,
                    hiddenFromHub: item.hiddenFromHub,
                }),
            );
        }

        for (const item of raw) {
            if (item.section !== 'config') {
                continue;
            }

            const groupId = navGroupId(item.group);

            sectionFor(groupId).pages.push(
                decorateConfigPage({
                    id: item.id ?? pathOf(item.href),
                    title: item.title,
                    href: pathOf(item.href),
                    icon: resolveIcon(item.icon, Settings),
                    hiddenFromHub: Boolean(item.hidden_from_hub),
                }),
            );
        }

        for (const section of ordered) {
            section.pages = sortConfigPages(section.id, section.pages);
        }

        return ordered.filter((section) => section.pages.length > 0);
    });

    const groups = computed((): SidebarGroup[] => {
        const byId = new Map<string, SidebarGroup>();

        for (const item of rawNav.value) {
            if (item.section === 'config') {
                continue;
            }

            const groupId = navGroupId(item.group);

            if (groupId === 'console') {
                continue;
            }

            let group = byId.get(groupId);

            if (!group) {
                group = {
                    id: groupId,
                    label: groupLabels[groupId] ?? groupId,
                    items: [],
                };
                byId.set(groupId, group);
            }

            group.items.push(sidebarItemFromRaw(item));
        }

        for (const group of byId.values()) {
            group.items.sort((a, b) => {
                const ah = a.children.length > 0 ? 1 : 0;
                const bh = b.children.length > 0 ? 1 : 0;

                return ah - bh;
            });
        }

        const ordered: SidebarGroup[] = [consoleGroup.value];

        for (const groupId of sidebarGroupOrder) {
            const group = byId.get(groupId);

            if (group && group.items.length > 0) {
                ordered.push(group);
                byId.delete(groupId);
            }
        }

        for (const group of byId.values()) {
            if (group.items.length > 0) {
                ordered.push(group);
            }
        }

        return ordered;
    });

    const pins = computed(
        (): SidebarItem[] =>
            groups.value.find((group) => group.id === 'console')?.items ?? [],
    );

    const domains = computed((): OpsDomain[] =>
        groups.value
            .filter((group) => group.id !== 'console')
            .map((group) => ({
                id: group.id,
                label: group.label,
                icon: opsDomainIcons[group.id] ?? Puzzle,
                items: group.items,
            })),
    );

    const destinations = computed((): NavDestination[] => {
        const out: NavDestination[] = [];
        const seen = new Set<string>();

        const push = (destination: NavDestination): void => {
            if (seen.has(destination.href)) {
                return;
            }

            seen.add(destination.href);
            out.push(destination);
        };

        for (const pin of pins.value) {
            push({
                id: pin.id,
                title: pin.title,
                href: pin.href,
                icon: pin.icon,
                group: 'Console',
                kind: 'ops',
            });
        }

        for (const domain of domains.value) {
            for (const item of domain.items) {
                if (item.children.length > 0) {
                    for (const child of item.children) {
                        push({
                            id: child.id,
                            title: child.title,
                            href: child.href,
                            icon: child.icon,
                            group: `${domain.label} · ${item.title}`,
                            kind: 'ops',
                        });
                    }
                } else {
                    push({
                        id: item.id,
                        title: item.title,
                        href: item.href,
                        icon: item.icon,
                        group: domain.label,
                        kind: 'ops',
                    });
                }
            }
        }

        push({
            id: 'config-hub',
            title: 'Configuration',
            href: CONFIG_HUB_PATH,
            icon: Settings,
            group: 'Configuration',
            kind: 'config',
        });

        for (const section of configSections.value) {
            for (const page of section.pages) {
                push({
                    id: page.id,
                    title: page.title,
                    href: page.href,
                    icon: page.icon,
                    group: `Configuration · ${section.label}`,
                    kind: 'config',
                });
            }
        }

        return out;
    });

    const currentPath = computed(
        () =>
            new URL(
                page.url,
                typeof window !== 'undefined'
                    ? window.location.origin
                    : 'http://localhost',
            ).pathname,
    );

    /*
     * Item actif = correspondance d'URL la plus longue, pour que
     * /admin/tickets/123 active « Tickets » et /admin/tlds/import
     * active « Import TLD » plutôt que « Extensions ».
     */
    const activeItemId = computed((): string | null => {
        let best: { id: string; length: number } | null = null;

        const consider = (id: string, path: string): void => {
            if (
                matches(currentPath.value, path) &&
                (!best || path.length > best.length)
            ) {
                best = { id, length: path.length };
            }
        };

        for (const group of groups.value) {
            for (const item of group.items) {
                for (const child of item.children) {
                    for (const path of child.paths) {
                        consider(child.id, path);
                    }
                }

                for (const path of item.paths) {
                    consider(item.id, path);
                }
            }
        }

        return best?.id ?? null;
    });

    const activeDomainId = computed((): string | null => {
        if (!activeItemId.value) {
            return null;
        }

        for (const domain of domains.value) {
            for (const item of domain.items) {
                if (
                    item.id === activeItemId.value ||
                    item.children.some(
                        (child) => child.id === activeItemId.value,
                    )
                ) {
                    return domain.id;
                }
            }
        }

        return null;
    });

    const activeHub = computed((): ActiveHub | null => {
        const raw = (page.props.platform as { nav?: RawNavItem[] })?.nav ?? [];
        let best: { item: RawNavItem; length: number } | null = null;

        for (const item of raw) {
            const pages = item.pages ?? [];

            if (pages.length === 0) {
                continue;
            }

            for (const href of [item.href, ...pages.map((p) => p.href)]) {
                const path = pathOf(href);

                if (
                    matches(currentPath.value, path) &&
                    (!best || path.length > best.length)
                ) {
                    best = { item, length: path.length };
                }
            }
        }

        if (!best) {
            return null;
        }

        const groupId = navGroupId(best.item.group);
        const pages = best.item.pages ?? [];
        let activePage: { id: string; length: number } | null = null;

        for (const hubPage of pages) {
            const path = pathOf(hubPage.href);

            if (
                matches(currentPath.value, path) &&
                (!activePage || path.length > activePage.length)
            ) {
                activePage = { id: hubPage.id ?? path, length: path.length };
            }
        }

        const hubIcon = resolveIcon(best.item.icon, Puzzle);

        return {
            id: best.item.id ?? pathOf(best.item.href),
            title: best.item.title,
            href: pathOf(best.item.href),
            icon: hubIcon,
            groupLabel: groupLabels[groupId] ?? groupId,
            pages: pages.map((hubPage) => {
                const href = pathOf(hubPage.href);

                return {
                    id: hubPage.id ?? href,
                    title: hubPage.title,
                    href,
                    icon: resolveIcon(hubPage.icon, hubIcon),
                    active: activePage?.id === (hubPage.id ?? href),
                };
            }),
        };
    });

    /*
     * L'espace Configuration est actif sur le hub et sur toutes
     * les pages référencées par une section de configuration.
     * Un hub d’extension (sous-nav interne) n’entre pas en mode Configuration.
     */
    const onConfigHub = computed((): boolean =>
        matches(currentPath.value, CONFIG_HUB_PATH),
    );

    const configActive = computed((): boolean => {
        if (activeHub.value) {
            return false;
        }

        if (onConfigHub.value) {
            return true;
        }

        return configSections.value.some((section) =>
            section.pages.some((p) => matches(currentPath.value, p.href)),
        );
    });

    const activeConfigId = computed((): string | null => {
        if (!configActive.value || onConfigHub.value) {
            return null;
        }

        let best: { id: string; length: number } | null = null;

        for (const section of configSections.value) {
            for (const p of section.pages) {
                if (
                    matches(currentPath.value, p.href) &&
                    (!best || p.href.length > best.length)
                ) {
                    best = { id: p.id, length: p.href.length };
                }
            }
        }

        return best?.id ?? null;
    });

    const activeConfigSection = computed((): ConfigSection | null => {
        if (!activeConfigId.value) {
            return null;
        }

        return (
            configSections.value.find((section) =>
                section.pages.some((page) => page.id === activeConfigId.value),
            ) ?? null
        );
    });

    const moduleConsoles = computed((): SidebarItem[] => {
        return (
            groups.value.find((group) => group.id === 'modules')?.items ?? []
        );
    });

    return {
        groups,
        pins,
        domains,
        destinations,
        activeItemId,
        activeDomainId,
        configSections,
        configActive,
        onConfigHub,
        activeConfigId,
        activeConfigSection,
        activeHub,
        moduleConsoles,
    };
}
