"use client";

/**
 * DepartmentPicker — 부서 선택 재사용 컴포넌트 (V1 신규).
 *
 * 다른 화면에서 부서를 선택해야 할 때 사용. 단일 / 다중 선택 모드 지원.
 *
 * 사용 예:
 *   <DepartmentPicker
 *     companyCode="INVYONE"
 *     mode="single"
 *     value={parentDeptCode}
 *     open={isOpen}
 *     onSelect={(code) => setParentDeptCode(code as string)}
 *     onClose={() => setIsOpen(false)}
 *     excludeCodes={[currentDeptCode]}
 *   />
 *
 * 동작:
 *   - shadcn Dialog 안에 검색박스 + 트리뷰
 *   - 부모 클릭 시 자식 cascade 펼침
 *   - 클라이언트측 검색 (debounce 200ms, 이름/코드 부분일치)
 *   - single: 클릭 즉시 onSelect → close
 *   - multi: 체크박스 + 부모 체크 시 자식 자동 cascade + 확인 버튼으로 onSelect
 *   - excludeCodes 에 포함된 dept 는 disabled
 *   - 사이클 데이터 (잘못된 PARENT_DEPT_CODE) 는 visited Set 으로 차단
 *
 * V1 한계: 검색은 클라이언트측 필터. 1000+ 부서는 V2 에서 backend search 도입 예정.
 */

import { useEffect, useMemo, useState } from "react";
import { Check, ChevronDown, ChevronRight, Search, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import type { Department } from "@/types/department";
import { getDepartments } from "@/lib/api/department";

export interface DepartmentPickerProps {
  companyCode: string;
  mode: "single" | "multi";
  /** 현재 선택값. single 이면 string, multi 면 string[] */
  value?: string | string[];
  open: boolean;
  onSelect: (code: string | string[]) => void;
  onClose: () => void;
  /** 선택 불가로 disable 처리할 dept_code 들 (자기 자신 부모 등록 방지 등) */
  excludeCodes?: string[];
  /** soft-delete 된 부서도 보여줄지 (default false) */
  includeDeleted?: boolean;
  /** 모달 헤더 타이틀 (default: "부서 선택") */
  title?: string;
  /** single 모드에서 "최상위로" (부모 없음) 옵션 표시 (default false) */
  allowRoot?: boolean;
}

export function DepartmentPicker({
  companyCode,
  mode,
  value,
  open,
  onSelect,
  onClose,
  excludeCodes,
  includeDeleted = false,
  title = "부서 선택",
  allowRoot = false,
}: DepartmentPickerProps) {
  const [departments, setDepartments] = useState<Department[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [searchInput, setSearchInput] = useState("");
  const [searchTerm, setSearchTerm] = useState(""); // debounced
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
  const [selected, setSelected] = useState<Set<string>>(new Set());

  // value -> selected 동기화
  useEffect(() => {
    if (!open) return;
    if (mode === "single") {
      setSelected(new Set(typeof value === "string" && value ? [value] : []));
    } else {
      setSelected(new Set(Array.isArray(value) ? value : []));
    }
  }, [value, mode, open]);

  // 검색어 debounce 200ms
  useEffect(() => {
    const t = setTimeout(() => setSearchTerm(searchInput.trim().toLowerCase()), 200);
    return () => clearTimeout(t);
  }, [searchInput]);

  // 부서 목록 로드
  useEffect(() => {
    if (!open) return;
    let cancelled = false;
    setIsLoading(true);
    getDepartments(companyCode, { includeDeleted })
      .then((res: any) => {
        if (cancelled) return;
        if (res?.success && Array.isArray(res?.data)) {
          setDepartments(res.data);
        } else {
          setDepartments([]);
        }
      })
      .catch(() => !cancelled && setDepartments([]))
      .finally(() => !cancelled && setIsLoading(false));
    return () => {
      cancelled = true;
    };
  }, [open, companyCode, includeDeleted]);

  // 코드 -> 부서 맵 (검색·자식 조회용)
  const byCode = useMemo(() => {
    const m = new Map<string, Department>();
    for (const d of departments) m.set(d.dept_code, d);
    return m;
  }, [departments]);

  // 검색 매칭 (이름·코드 부분일치)
  const isMatch = (d: Department): boolean => {
    if (!searchTerm) return true;
    return (
      d.dept_name.toLowerCase().includes(searchTerm) ||
      d.dept_code.toLowerCase().includes(searchTerm)
    );
  };

  // 검색 매칭 부서 + 그 조상들도 포함해서 트리에서 visible
  const visibleCodes = useMemo(() => {
    if (!searchTerm) return null; // null = 전체 visible
    const visible = new Set<string>();
    for (const d of departments) {
      if (isMatch(d)) {
        visible.add(d.dept_code);
        // 조상 visible (부모-부모-...) — 사이클 차단
        const visited = new Set<string>([d.dept_code]);
        let parentCode = d.parent_dept_code;
        while (parentCode && !visited.has(parentCode)) {
          visited.add(parentCode);
          visible.add(parentCode);
          parentCode = byCode.get(parentCode)?.parent_dept_code ?? null;
        }
      }
    }
    return visible;
  }, [searchTerm, departments, byCode]);

  // 부모 코드 → 자식 정렬 리스트
  const childrenOf = (parentCode: string | null): Department[] => {
    return departments
      .filter((d) => (d.parent_dept_code ?? null) === parentCode)
      .sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0));
  };

  // 부모 + 자식 (재귀) cascade 코드들
  const collectDescendants = (rootCode: string): string[] => {
    const result: string[] = [];
    const visited = new Set<string>();
    const dfs = (code: string) => {
      if (visited.has(code)) return;
      visited.add(code);
      result.push(code);
      for (const child of childrenOf(code)) {
        dfs(child.dept_code);
      }
    };
    dfs(rootCode);
    return result;
  };

  const toggleExpand = (code: string) => {
    const next = new Set(expanded);
    if (next.has(code)) next.delete(code);
    else next.add(code);
    setExpanded(next);
  };

  const isExcluded = (code: string) => Boolean(excludeCodes?.includes(code));
  const isDeleted = (d: Department) => Boolean((d as any).deleted_at);

  const handleNodeClick = (d: Department) => {
    if (isExcluded(d.dept_code)) return;
    if (mode === "single") {
      onSelect(d.dept_code);
      onClose();
      return;
    }
    // multi: 자기 + 자손 모두 토글
    const next = new Set(selected);
    const codes = collectDescendants(d.dept_code).filter((c) => !isExcluded(c));
    const allSelected = codes.every((c) => next.has(c));
    if (allSelected) {
      for (const c of codes) next.delete(c);
    } else {
      for (const c of codes) next.add(c);
    }
    setSelected(next);
  };

  const handleConfirmMulti = () => {
    onSelect(Array.from(selected));
    onClose();
  };

  // 트리 렌더 (재귀, visited Set 사이클 차단)
  const renderTree = (parentCode: string | null, level: number, visited: Set<string>): React.ReactNode => {
    const list = childrenOf(parentCode);
    return list.map((d) => {
      if (visited.has(d.dept_code)) return null; // 사이클 차단
      const nextVisited = new Set(visited);
      nextVisited.add(d.dept_code);

      const hasChildren = childrenOf(d.dept_code).length > 0;
      const isOpen = expanded.has(d.dept_code) || (searchTerm.length > 0 && hasChildren);
      const isSel = selected.has(d.dept_code);
      const excluded = isExcluded(d.dept_code);
      const deleted = isDeleted(d);

      // 검색 시: visible 아닌 노드는 숨김
      if (visibleCodes && !visibleCodes.has(d.dept_code)) return null;

      return (
        <div key={d.dept_code}>
          <div
            className={`flex items-center gap-2 rounded p-1.5 text-sm transition-colors ${
              excluded
                ? "cursor-not-allowed opacity-40"
                : "hover:bg-muted cursor-pointer"
            } ${isSel ? "bg-primary/10 text-primary" : ""} ${deleted ? "text-muted-foreground line-through" : ""}`}
            style={{ paddingLeft: `${level * 16 + 6}px` }}
            onClick={() => handleNodeClick(d)}
          >
            {/* expand/collapse */}
            {hasChildren ? (
              <button
                onClick={(e) => {
                  e.stopPropagation();
                  toggleExpand(d.dept_code);
                }}
                className="flex h-4 w-4 items-center justify-center"
              >
                {isOpen ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
              </button>
            ) : (
              <div className="h-4 w-4" />
            )}

            {/* multi: 체크 표시 */}
            {mode === "multi" && (
              <div
                className={`flex h-4 w-4 items-center justify-center rounded border ${
                  isSel ? "bg-primary border-primary text-primary-foreground" : "border-input"
                }`}
              >
                {isSel && <Check className="h-3 w-3" />}
              </div>
            )}

            {/* 부서명 + 코드 */}
            <div className="flex flex-1 flex-col leading-tight">
              <span className="font-medium">{d.dept_name}</span>
              <span className="text-muted-foreground text-[10px] uppercase">{d.dept_code}</span>
            </div>

            {deleted && (
              <span className="text-muted-foreground text-[10px] uppercase tracking-wider">삭제됨</span>
            )}
          </div>

          {hasChildren && isOpen && renderTree(d.dept_code, level + 1, nextVisited)}
        </div>
      );
    });
  };

  // 루트 — parent_dept_code 가 null/빈문자열인 부서들
  const rootList = useMemo(() => childrenOf(null), [departments]);
  const hasAny = rootList.length > 0 || departments.some((d) => !d.parent_dept_code);
  const noResults = searchTerm.length > 0 && (visibleCodes?.size ?? 0) === 0;

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent className="max-w-[95vw] sm:max-w-[480px]">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
        </DialogHeader>

        <div className="space-y-3">
          {/* 검색 */}
          <div className="relative">
            <Search className="text-muted-foreground absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2" />
            <Input
              value={searchInput}
              onChange={(e) => setSearchInput(e.target.value)}
              placeholder="부서명 또는 코드로 검색"
              className="pl-8 pr-8"
              autoFocus
            />
            {searchInput && (
              <button
                onClick={() => setSearchInput("")}
                className="text-muted-foreground absolute right-2 top-1/2 -translate-y-1/2"
                title="검색어 지우기"
              >
                <X className="h-4 w-4" />
              </button>
            )}
          </div>

          {/* 트리 */}
          <div className="bg-card max-h-[50vh] overflow-y-auto rounded border p-2">
            {mode === "single" && allowRoot && !isLoading && (
              <button
                type="button"
                onClick={() => {
                  onSelect("");
                  onClose();
                }}
                className="bg-muted/30 hover:bg-muted mb-1 w-full rounded p-1.5 text-left text-sm font-medium text-muted-foreground"
              >
                📂 (최상위 — 부모 없음)
              </button>
            )}
            {isLoading ? (
              <div className="text-muted-foreground py-8 text-center text-sm">로딩 중...</div>
            ) : !hasAny ? (
              <div className="text-muted-foreground py-8 text-center text-sm">부서가 없습니다.</div>
            ) : noResults ? (
              <div className="text-muted-foreground py-8 text-center text-sm">검색 결과 없음</div>
            ) : (
              renderTree(null, 0, new Set())
            )}
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={onClose}>
            취소
          </Button>
          {mode === "multi" && (
            <Button onClick={handleConfirmMulti} disabled={selected.size === 0}>
              선택 ({selected.size})
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

export default DepartmentPicker;
