'use client';

import { usePathname } from 'next/navigation';
import { useCallback, useState } from 'react';

/** 사이드바 최상위 링크 노드 — 그룹에 속하지 않는 단일 링크(예: 홈). */
export interface SidebarNavLink {
  type: 'link';
  label: string;
  href: string;
}

/** 사이드바 그룹 노드 — 라우트가 없는 헤딩이며, 자식 링크를 펼침/접힘으로 보여준다. */
export interface SidebarNavGroup {
  type: 'group';
  label: string;
  children: SidebarNavLink[];
}

export type SidebarNavNode = SidebarNavLink | SidebarNavGroup;

export interface SidebarNavState {
  /** href가 현재 경로와 일치하는가(활성 링크 여부). */
  isLinkActive: (href: string) => boolean;
  /** 그룹 라벨이 현재 펼침 상태인가. */
  isGroupExpanded: (label: string) => boolean;
  /** 그룹 펼침/접힘을 토글한다. */
  toggleGroup: (label: string) => void;
}

/** tree에서 현재 pathname을 자식으로 포함하는 그룹의 라벨을 찾는다(없으면 null). */
function findActiveGroupLabel(
  tree: SidebarNavNode[],
  pathname: string
): string | null {
  const activeGroup = tree.find(
    (node): node is SidebarNavGroup =>
      node.type === 'group' &&
      node.children.some((link) => link.href === pathname)
  );
  return activeGroup?.label ?? null;
}

/**
 * 사이드바 내비게이션 트리의 화면 로컬 상태(ViewModel 대응) — 그룹 라벨을 키로 펼침/접힘
 * 여부를 들고 있고, 현재 경로 기준 활성 링크·활성 그룹 판정도 함께 제공한다. 트리 데이터
 * 자체는 호출부가 소유하고 이 훅에 넘긴다(이 훅은 상태·판정 로직만 책임).
 *
 * 현재 경로가 속한 그룹은 항상 펼쳐져 있어야 한다(기획 ADM_MEM_101). 최초 렌더뿐 아니라
 * 클라이언트 내비게이션으로 pathname이 바뀌는 매 순간에도 이 불변식을 지켜야 하므로,
 * `use-sidebar.ts`(모바일 오버레이를 pathname 변화에 맞춰 닫는 로직)가 쓰는 것과 동일한
 * "렌더 중 상태 조정" 패턴(pathname 파생값의 변화를 렌더 중 감지해 즉시 setState)을 쓴다 —
 * effect 안에서 setState하면 `react-hooks/set-state-in-effect` 린트 규칙에 걸리고
 * effect발 cascading render를 유발하므로 이 프로젝트에서는 쓰지 않는다.
 *
 * 사용자가 수동으로 접은 그룹을 강제로 다시 펼치지는 않는다 — activeGroupLabel 자체가
 * 바뀔 때만(= 다른 그룹의 경로로 새로 이동했을 때만) 그 그룹을 편다. 같은 그룹 내 다른
 * 링크로 이동하는 경우(activeGroupLabel 불변)에는 사용자가 접어둔 상태를 그대로 둔다.
 */
export function useSidebarNav(tree: SidebarNavNode[]): SidebarNavState {
  const pathname = usePathname();
  const activeGroupLabel = findActiveGroupLabel(tree, pathname);

  const [expandedGroups, setExpandedGroups] = useState<
    Record<string, boolean>
  >(() => (activeGroupLabel ? { [activeGroupLabel]: true } : {}));

  const [prevActiveGroupLabel, setPrevActiveGroupLabel] =
    useState(activeGroupLabel);
  if (activeGroupLabel !== prevActiveGroupLabel) {
    setPrevActiveGroupLabel(activeGroupLabel);
    if (activeGroupLabel !== null) {
      setExpandedGroups((prev) => ({ ...prev, [activeGroupLabel]: true }));
    }
  }

  const isLinkActive = useCallback(
    (href: string) => pathname === href,
    [pathname]
  );

  const isGroupExpanded = useCallback(
    (label: string) => Boolean(expandedGroups[label]),
    [expandedGroups]
  );

  const toggleGroup = useCallback((label: string) => {
    setExpandedGroups((prev) => ({ ...prev, [label]: !prev[label] }));
  }, []);

  return { isLinkActive, isGroupExpanded, toggleGroup };
}
