'use client';

import { usePathname } from 'next/navigation';
import { useCallback, useMemo, useState } from 'react';
import type {
  SidebarMenu,
  SidebarMenuChild,
  SidebarMenuItem,
} from '@/lib/domain/sidebar-menu';

/**
 * 사이드바 펼침·활성 상태(ViewModel). 트리는 서버가 준 값을 그대로 받고, 이 훅은 "지금 어디에
 * 있는가"와 "무엇이 펼쳐져 있는가"만 판정한다.
 *
 * 펼침은 **현재 경로에서 파생된 기본값 + 사용자가 누른 값**의 2층이다. 그래서 링크를 눌러
 * 이동하면 그 가지가 저절로 열리고, 사용자가 직접 접으면 그 선택이 유지된다. 열림 목록을
 * 상태로만 들고 있으면 이동할 때마다 손으로 다시 열어야 한다.
 */
export interface SidebarNavState {
  /** 이 href가 현재 경로인가. */
  isActive: (href?: string) => boolean;
  /** 1depth 항목이 펼쳐져 있는가. */
  isItemOpen: (item: SidebarMenuItem) => boolean;
  toggleItem: (id: string) => void;
  /** 2depth 항목이 펼쳐져 있는가. */
  isChildOpen: (child: SidebarMenuChild) => boolean;
  toggleChild: (id: string) => void;
  /** 자손 중에 현재 경로가 있는가 — 1depth를 활성으로 칠할지 판단한다. */
  containsActive: (item: SidebarMenuItem) => boolean;
}

function childContainsPath(child: SidebarMenuChild, pathname: string): boolean {
  return (
    child.href === pathname ||
    (child.children?.some((leaf) => leaf.href === pathname) ?? false)
  );
}

function itemContainsPath(item: SidebarMenuItem, pathname: string): boolean {
  return (
    item.href === pathname ||
    (item.children?.some((child) => childContainsPath(child, pathname)) ?? false)
  );
}

export function useSidebarNav(menu: SidebarMenu): SidebarNavState {
  const pathname = usePathname();
  // 사용자가 직접 누른 것만 담는다. 없으면 경로에서 파생된 기본값을 쓴다.
  const [itemOverrides, setItemOverrides] = useState<Record<string, boolean>>({});
  const [childOverrides, setChildOverrides] = useState<Record<string, boolean>>(
    {}
  );

  // 현재 경로를 품은 가지 — 기본 펼침 대상이다.
  const openByPath = useMemo(() => {
    const items = new Set<string>();
    const children = new Set<string>();

    for (const section of menu.sections) {
      for (const item of section.items) {
        if (!itemContainsPath(item, pathname)) {
          continue;
        }
        items.add(item.id);
        for (const child of item.children ?? []) {
          if (childContainsPath(child, pathname)) {
            children.add(child.id);
          }
        }
      }
    }

    return { items, children };
  }, [menu, pathname]);

  const isActive = useCallback(
    (href?: string) => href !== undefined && href === pathname,
    [pathname]
  );

  const isItemOpen = useCallback(
    (item: SidebarMenuItem) =>
      itemOverrides[item.id] ?? openByPath.items.has(item.id),
    [itemOverrides, openByPath]
  );

  const isChildOpen = useCallback(
    (child: SidebarMenuChild) =>
      childOverrides[child.id] ?? openByPath.children.has(child.id),
    [childOverrides, openByPath]
  );

  const toggleItem = useCallback(
    (id: string) =>
      setItemOverrides((prev) => ({
        ...prev,
        [id]: !(prev[id] ?? openByPath.items.has(id)),
      })),
    [openByPath]
  );

  const toggleChild = useCallback(
    (id: string) =>
      setChildOverrides((prev) => ({
        ...prev,
        [id]: !(prev[id] ?? openByPath.children.has(id)),
      })),
    [openByPath]
  );

  const containsActive = useCallback(
    (item: SidebarMenuItem) => itemContainsPath(item, pathname),
    [pathname]
  );

  return {
    isActive,
    isItemOpen,
    toggleItem,
    isChildOpen,
    toggleChild,
    containsActive,
  };
}
