'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Link from 'next/link';
import { PanelTop } from 'lucide-react';
import { ICON_SIZE_MD } from '@/components/icons';
import { ProjetoMenuFaIcon } from './ProjetoMenuFaIcon';
import { ProjetoMenuBadge } from './ProjetoMenuBadge';
import { SidebarMenuIcon } from '../Sidebar/SidebarMenuIcon';
import {
    findActiveRootNode,
    groupsToMenuNodes,
    isProjetoMenuItemActive,
    nodeContainsActive,
    type ProjetoMenuNode,
} from './projetoMenuNavigation';
import type { MenuGroupConfig } from './projetoMenuTypes';
import styles from './ProjetoLayout.module.scss';

export interface ProjetoMenuAsideProps {
    projetoId: string;
    currentPath: string;
    menuGroups: MenuGroupConfig[];
    /**
     * A rota já tem coluna própria à esquerda (Planejamento / `pageAside`): o
     * aside encolhe para rail de ícones e só expande em hover/foco, para não
     * criar duas trilhas verticais competindo pela mesma leitura.
     */
    rail?: boolean;
    /** Tipologia/addons ainda a resolver: esqueleto em vez de coluna vazia. */
    carregando?: boolean;
    onDeleteProjeto: () => void;
    /** Volta ao menu em barra horizontal sem passar pelo menu do usuário. */
    onAlternarOrientacao?: () => void;
}

function renderBadges(node: ProjetoMenuNode) {
    return (
        <>
            {node.new ? <ProjetoMenuBadge variant="new" /> : null}
            {node.emBreve ? <ProjetoMenuBadge variant="emBreve" /> : null}
            {node.badgeCount != null && node.badgeCount > 0 ? (
                <ProjetoMenuBadge variant="count" count={node.badgeCount} />
            ) : null}
        </>
    );
}

/**
 * Menu do projeto no eixo vertical: coluna fixa à esquerda com drill-in
 * Grupo › Seção › Item. Alternativa à barra horizontal (`ProjetoMenuNav`),
 * escolhida pelo usuário e guardada por dispositivo.
 */
export function ProjetoMenuAside({
    projetoId,
    currentPath,
    menuGroups,
    rail = false,
    carregando = false,
    onDeleteProjeto,
    onAlternarOrientacao,
}: ProjetoMenuAsideProps) {
    const [drillIds, setDrillIds] = useState<string[]>([]);
    const backButtonRef = useRef<HTMLButtonElement | null>(null);
    const drillDepthRef = useRef(0);

    const rootNodes = useMemo(() => groupsToMenuNodes(menuGroups), [menuGroups]);

    /*
     * A pilha guarda ids, não nós: o menu é reconstruído a cada mudança de addon,
     * status ou badge, e uma pilha de objetos ficaria a apontar para árvores antigas.
     */
    const drillStack = useMemo(() => {
        const stack: ProjetoMenuNode[] = [];
        let nivel = rootNodes;
        for (const id of drillIds) {
            const encontrado = nivel.find((node) => node.id === id);
            if (!encontrado?.children?.length) break;
            stack.push(encontrado);
            nivel = encontrado.children;
        }
        return stack;
    }, [drillIds, rootNodes]);

    const activeRootId = useMemo(
        () => findActiveRootNode(rootNodes, projetoId, currentPath)?.id ?? null,
        [rootNodes, projetoId, currentPath],
    );

    /*
     * Ao mudar o grupo da rota ativa, o aside segue a navegação. Comparar com o
     * último grupo aplicado preserva o drill manual enquanto o usuário explora
     * outro grupo sem sair da página.
     */
    const grupoAplicadoRef = useRef<string | null>(null);
    useEffect(() => {
        if (activeRootId === grupoAplicadoRef.current) return;
        grupoAplicadoRef.current = activeRootId;
        setDrillIds(activeRootId ? [activeRootId] : []);
    }, [activeRootId]);

    useEffect(() => {
        const anterior = drillDepthRef.current;
        drillDepthRef.current = drillStack.length;
        if (drillStack.length > anterior && drillStack.length > 0) {
            backButtonRef.current?.focus({ preventScroll: true });
        }
    }, [drillStack.length]);

    const drillIn = useCallback((node: ProjetoMenuNode) => {
        if (!node.children?.length) return;
        setDrillIds((prev) => [...prev, node.id]);
    }, []);

    const drillOut = useCallback(() => {
        setDrillIds((prev) => prev.slice(0, -1));
    }, []);

    const nivelAtual = drillStack[drillStack.length - 1];
    const nodesVisiveis = nivelAtual?.children ?? rootNodes;
    const tituloNivelAnterior =
        drillStack.length > 1 ? drillStack[drillStack.length - 2].label : 'Menu do projeto';

    const renderRow = (node: ProjetoMenuNode, index: number) => {
        const temFilhos = Boolean(node.children?.length);
        const folhaAtiva = isProjetoMenuItemActive(node.route, projetoId, currentPath);
        const ramoAtivo = temFilhos && nodeContainsActive(node, projetoId, currentPath);
        const isDanger = Boolean(node.danger);

        if (temFilhos) {
            return (
                <li key={`${node.id}-${index}`}>
                    <button
                        type="button"
                        className={`${styles.asideVerticalRow} ${ramoAtivo ? styles.asideVerticalRowActive : ''}`}
                        onClick={() => drillIn(node)}
                        aria-haspopup="true"
                    >
                        <ProjetoMenuFaIcon iconClass={node.icon} className={styles.asideVerticalIcon} />
                        <span className={styles.asideVerticalLabel}>{node.label}</span>
                        <span className={styles.asideVerticalTrail}>
                            {renderBadges(node)}
                            <SidebarMenuIcon icon="angleRight" className={styles.asideVerticalChevron} />
                        </span>
                    </button>
                </li>
            );
        }

        if (node.action === 'excluir-projeto') {
            return (
                <li key={`${node.id}-${index}`}>
                    <button
                        type="button"
                        className={`${styles.asideVerticalRow} ${isDanger ? styles.asideVerticalRowDanger : ''}`}
                        onClick={onDeleteProjeto}
                    >
                        <ProjetoMenuFaIcon iconClass={node.icon} className={styles.asideVerticalIcon} />
                        <span className={styles.asideVerticalLabel}>{node.label}</span>
                    </button>
                </li>
            );
        }

        // `pruneEmptyMenuItems` garante que folhas sem página e sem ação não chegam aqui.
        if (!node.route || node.route === '#') return null;

        return (
            <li key={`${node.id}-${index}`}>
                <Link
                    href={node.route}
                    prefetch={false}
                    className={`${styles.asideVerticalRow} ${folhaAtiva ? styles.asideVerticalRowActive : ''} ${isDanger ? styles.asideVerticalRowDanger : ''}`}
                    aria-current={folhaAtiva ? ('page' as const) : undefined}
                >
                    <ProjetoMenuFaIcon iconClass={node.icon} className={styles.asideVerticalIcon} />
                    <span className={styles.asideVerticalLabel}>{node.label}</span>
                    <span className={styles.asideVerticalTrail}>{renderBadges(node)}</span>
                </Link>
            </li>
        );
    };

    return (
        <aside
            className={`${styles.asideVertical}${rail ? ` ${styles.asideVerticalRail}` : ''}`}
            aria-label={carregando ? 'Menu do projeto carregando' : 'Menu do projeto'}
            aria-busy={carregando || undefined}
            data-testid="projeto-menu-aside"
            data-rail={rail ? '1' : undefined}
            data-drill-depth={drillStack.length}
        >
            <div className={styles.asideVerticalHeader}>
                {nivelAtual && !carregando ? (
                    <button
                        type="button"
                        ref={backButtonRef}
                        className={styles.asideVerticalBackBtn}
                        onClick={drillOut}
                        aria-label={`Voltar para ${tituloNivelAnterior}`}
                        data-testid="projeto-menu-aside-voltar"
                    >
                        <SidebarMenuIcon icon="arrowLeft" />
                        <span className={styles.asideVerticalBackLabel}>{tituloNivelAnterior}</span>
                    </button>
                ) : (
                    <span className={styles.asideVerticalTitulo}>Menu do projeto</span>
                )}
            </div>

            {nivelAtual && !carregando ? (
                <p className={styles.asideVerticalNivelLabel}>{nivelAtual.label}</p>
            ) : null}

            {carregando ? (
                <div className={styles.asideVerticalSkeleton} aria-hidden data-testid="projeto-menu-aside-skeleton">
                    {Array.from({ length: 6 }, (_, index) => (
                        <span key={index} className={styles.asideVerticalSkeletonRow} />
                    ))}
                </div>
            ) : (
                <nav
                    className={styles.asideVerticalScroll}
                    aria-label={nivelAtual ? nivelAtual.label : 'Seções do projeto'}
                >
                    <ul className={styles.asideVerticalList}>
                        {nodesVisiveis.map((node, index) => renderRow(node, index))}
                    </ul>
                </nav>
            )}

            {onAlternarOrientacao ? (
                <div className={styles.asideVerticalFooter}>
                    <button
                        type="button"
                        className={styles.asideVerticalRow}
                        onClick={onAlternarOrientacao}
                        data-testid="projeto-menu-aside-horizontal"
                    >
                        <PanelTop
                            size={ICON_SIZE_MD}
                            className={styles.asideVerticalIcon}
                            aria-hidden
                        />
                        <span className={styles.asideVerticalLabel}>Menu superior</span>
                    </button>
                </div>
            ) : null}
        </aside>
    );
}
