"use client";

import { useEffect, useEffectEvent, useState, type ChangeEvent } from "react";

import { CloseIconButton } from "@/components/close-icon-button";
import type {
  MailboxContact,
  MailboxContactDuplicateGroup,
  MailboxContactImportCandidate,
  MailboxContactInput,
  MailboxContactSettings
} from "@/lib/official-mail";

export type ContactToolsMode = "duplicates" | "export" | "file" | "mail";

type Props = {
  mode: ContactToolsMode;
  onChanged: (message: string) => Promise<void> | void;
  onClose: () => void;
  onError: (message: string) => void;
  selectedContacts: MailboxContact[];
  settings: MailboxContactSettings;
};

async function responseError(response: Response, fallback: string) {
  const payload = (await response.json().catch(() => null)) as { message?: string } | null;
  return payload?.message ?? fallback;
}

function SelectionTable({
  contacts,
  selected,
  setSelected,
  showCount = false
}: {
  contacts: Array<MailboxContactInput & { interactionCount?: number }>;
  selected: Set<string>;
  setSelected: (next: Set<string>) => void;
  showCount?: boolean;
}) {
  const allSelected = contacts.length > 0 && contacts.every((contact) => selected.has(contact.email));
  return (
    <div className="max-h-[330px] overflow-auto border-y border-[#e7edf7]">
      <div className={`grid ${showCount ? "grid-cols-[36px_minmax(110px,1fr)_minmax(190px,1.5fr)_76px_100px]" : "grid-cols-[36px_minmax(110px,1fr)_minmax(190px,1.5fr)_110px]"} sticky top-0 z-10 bg-[#f8fafd] px-3 text-[11px] font-semibold text-[#687991]`}>
        <label className="flex items-center py-2.5"><input aria-label="전체 선택" type="checkbox" checked={allSelected} onChange={(event) => setSelected(event.target.checked ? new Set(contacts.map((contact) => contact.email)) : new Set())} className="h-4 w-4 accent-[#2f6df6]" /></label>
        <span className="py-2.5">이름</span><span className="py-2.5">이메일</span>{showCount ? <span className="py-2.5">교신</span> : null}<span className="py-2.5">그룹</span>
      </div>
      {contacts.length === 0 ? <div className="px-4 py-16 text-center text-[12px] text-[#8290a7]">표시할 연락처가 없습니다.</div> : contacts.map((contact) => (
        <label key={contact.email} className={`grid ${showCount ? "grid-cols-[36px_minmax(110px,1fr)_minmax(190px,1.5fr)_76px_100px]" : "grid-cols-[36px_minmax(110px,1fr)_minmax(190px,1.5fr)_110px]"} cursor-pointer items-center border-t border-[#edf2f7] px-3 text-[12px] first:border-t-0 hover:bg-[#f8fbff]`}>
          <span className="py-2.5"><input type="checkbox" checked={selected.has(contact.email)} onChange={(event) => { const next = new Set(selected); if (event.target.checked) next.add(contact.email); else next.delete(contact.email); setSelected(next); }} className="h-4 w-4 accent-[#2f6df6]" /></span>
          <span className="truncate py-2.5 pr-3 font-medium text-[#2b3d5b]">{contact.displayName || "이름없음"}</span>
          <span className="truncate py-2.5 pr-3 text-[#50617d]">{contact.email}</span>
          {showCount ? <span className="py-2.5 text-[#60738f]">{contact.interactionCount ?? 0}회</span> : null}
          <span className="truncate py-2.5 text-[#74839b]">{contact.groupName || "-"}</span>
        </label>
      ))}
    </div>
  );
}

export function MailAddressBookToolsPanel({ mode, onChanged, onClose, onError, selectedContacts, settings }: Props) {
  const [busy, setBusy] = useState(false);
  const [fileRows, setFileRows] = useState<MailboxContactInput[]>([]);
  const [mailRows, setMailRows] = useState<MailboxContactImportCandidate[]>([]);
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [groupName, setGroupName] = useState("");
  const [duplicateMode, setDuplicateMode] = useState<"skip" | "update">("skip");
  const [months, setMonths] = useState(6);
  const [minCount, setMinCount] = useState(2);
  const [format, setFormat] = useState<"csv" | "vcard" | "xlsx">("csv");
  const [exportTarget, setExportTarget] = useState(selectedContacts.length > 0 ? "selected" : "all");
  const [exportGroup, setExportGroup] = useState(settings.groups[0] ?? "");
  const [exportFields, setExportFields] = useState(new Set(["displayName", "email", "phone", "companyName", "groupName", "memo"]));
  const [duplicateGroups, setDuplicateGroups] = useState<MailboxContactDuplicateGroup[]>([]);

  const loadDuplicates = async () => {
    if (mode !== "duplicates") return;
    setBusy(true);
    try {
      const response = await fetch("/api/mailbox/contacts/tools?action=duplicates", { cache: "no-store" });
      const payload = (await response.json().catch(() => null)) as { groups?: MailboxContactDuplicateGroup[]; message?: string; ok?: boolean } | null;
      if (!response.ok || !payload?.ok) throw new Error(payload?.message ?? "중복 연락처를 확인하지 못했습니다.");
      setDuplicateGroups(payload.groups ?? []);
    } catch (error) {
      onError(error instanceof Error ? error.message : "중복 연락처를 확인하지 못했습니다.");
    } finally {
      setBusy(false);
    }
  };
  const loadDuplicatesEffect = useEffectEvent(loadDuplicates);
  useEffect(() => {
    const timer = window.setTimeout(() => void loadDuplicatesEffect(), 0);
    return () => window.clearTimeout(timer);
  }, [mode]);

  const previewFile = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;
    setBusy(true);
    try {
      const formData = new FormData();
      formData.set("file", file);
      const response = await fetch("/api/mailbox/contacts/tools", { body: formData, method: "POST" });
      const payload = (await response.json().catch(() => null)) as { message?: string; ok?: boolean; rows?: MailboxContactInput[] } | null;
      if (!response.ok || !payload?.ok) throw new Error(payload?.message ?? "파일을 불러오지 못했습니다.");
      const rows = payload.rows ?? [];
      setFileRows(rows);
      setSelected(new Set(rows.map((row) => row.email)));
    } catch (error) {
      onError(error instanceof Error ? error.message : "파일을 불러오지 못했습니다.");
    } finally {
      setBusy(false);
      event.target.value = "";
    }
  };

  const loadMailCandidates = async () => {
    setBusy(true);
    try {
      const response = await fetch(`/api/mailbox/contacts/tools?action=mail-candidates&months=${months}&minCount=${minCount}`, { cache: "no-store" });
      const payload = (await response.json().catch(() => null)) as { candidates?: MailboxContactImportCandidate[]; message?: string; ok?: boolean } | null;
      if (!response.ok || !payload?.ok) throw new Error(payload?.message ?? "메일에서 연락처를 불러오지 못했습니다.");
      const rows = payload.candidates ?? [];
      setMailRows(rows);
      setSelected(new Set(rows.map((row) => row.email)));
    } catch (error) {
      onError(error instanceof Error ? error.message : "메일에서 연락처를 불러오지 못했습니다.");
    } finally {
      setBusy(false);
    }
  };

  const importContacts = async (contacts: MailboxContactInput[]) => {
    const chosen = contacts.filter((contact) => selected.has(contact.email)).map((contact) => ({
      ...contact,
      groupName: groupName || contact.groupName || ""
    }));
    if (chosen.length === 0) return onError("저장할 연락처를 선택해주세요.");
    setBusy(true);
    try {
      const response = await fetch("/api/mailbox/contacts/tools", {
        body: JSON.stringify({ action: "import", contacts: chosen, duplicateMode }),
        headers: { "Content-Type": "application/json" },
        method: "POST"
      });
      if (!response.ok) throw new Error(await responseError(response, "연락처를 저장하지 못했습니다."));
      await onChanged(`${chosen.length.toLocaleString("ko-KR")}개의 연락처를 저장했습니다.`);
      onClose();
    } catch (error) {
      onError(error instanceof Error ? error.message : "연락처를 저장하지 못했습니다.");
    } finally {
      setBusy(false);
    }
  };

  const exportContacts = async () => {
    const emails = exportTarget === "selected"
      ? selectedContacts.map((contact) => contact.email)
      : exportTarget === "group"
        ? settings.contacts.filter((contact) => contact.groupName === exportGroup).map((contact) => contact.email)
        : [];
    setBusy(true);
    try {
      const response = await fetch("/api/mailbox/contacts/tools", {
        body: JSON.stringify({ action: "export", emails, fields: [...exportFields], format }),
        headers: { "Content-Type": "application/json" },
        method: "POST"
      });
      if (!response.ok) throw new Error(await responseError(response, "주소록 파일을 만들지 못했습니다."));
      const blob = await response.blob();
      const disposition = response.headers.get("Content-Disposition") ?? "";
      const fileName = disposition.match(/filename="([^"]+)"/)?.[1] ?? `officialmail-contacts.${format}`;
      const url = URL.createObjectURL(blob);
      const anchor = document.createElement("a");
      anchor.href = url;
      anchor.download = fileName;
      anchor.click();
      window.setTimeout(() => URL.revokeObjectURL(url), 1_000);
      await onChanged("주소록 파일을 만들었습니다.");
    } catch (error) {
      onError(error instanceof Error ? error.message : "주소록 파일을 만들지 못했습니다.");
    } finally {
      setBusy(false);
    }
  };

  const mergeGroup = async (group: MailboxContactDuplicateGroup) => {
    const ids = group.contacts.map((contact) => contact.id).filter((id): id is number => Boolean(id));
    setBusy(true);
    try {
      const response = await fetch("/api/mailbox/contacts/tools", {
        body: JSON.stringify({ action: "merge", contactIds: ids }),
        headers: { "Content-Type": "application/json" },
        method: "POST"
      });
      if (!response.ok) throw new Error(await responseError(response, "중복 연락처를 병합하지 못했습니다."));
      await onChanged(`${group.contacts.length}개의 중복 연락처를 병합했습니다.`);
      await loadDuplicates();
    } catch (error) {
      onError(error instanceof Error ? error.message : "중복 연락처를 병합하지 못했습니다.");
    } finally {
      setBusy(false);
    }
  };

  const title = mode === "file" ? "파일에서 연락처 불러오기" : mode === "mail" ? "메일에서 연락처 불러오기" : mode === "export" ? "연락처 저장 · 내보내기" : "중복 연락처 정리";
  const rows = mode === "file" ? fileRows : mailRows;

  return (
    <div className="min-h-[560px] bg-white">
      <div className="flex items-start justify-between border-b border-[#e7edf7] px-5 py-4">
        <div><h2 className="text-[17px] font-semibold text-[#1c2b45]">{title}</h2><p className="mt-1 text-[12px] text-[#74839b]">네이버·구글·아웃룩 등 다른 주소록과 오피셜메일 주소를 안전하게 옮길 수 있습니다.</p></div>
        <CloseIconButton ariaLabel="주소록 도구 닫기" onClick={onClose} />
      </div>

      {mode === "file" || mode === "mail" ? <>
        <div className="flex flex-wrap items-end gap-3 px-5 py-4">
          {mode === "file" ? <label className="block"><span className="mb-1.5 block text-[11px] font-semibold text-[#60738f]">주소록 파일</span><input type="file" accept=".csv,.txt,.vcf,.vcard,.xls,.xlsx" disabled={busy} onChange={(event) => void previewFile(event)} className="block max-w-[280px] text-[12px] text-[#52637f] file:mr-3 file:cursor-pointer file:rounded-[8px] file:border-0 file:bg-[#edf4ff] file:px-3 file:py-2 file:font-semibold file:text-[#2f6df6]" /></label> : <>
            <label><span className="mb-1.5 block text-[11px] font-semibold text-[#60738f]">최근 기간</span><select value={months} onChange={(event) => setMonths(Number(event.target.value))} className="h-9 rounded-[8px] border border-[#d8e1ef] bg-white px-3 text-[12px]"><option value={1}>1개월</option><option value={3}>3개월</option><option value={6}>6개월</option><option value={12}>1년</option><option value={120}>제한 없음</option></select></label>
            <label><span className="mb-1.5 block text-[11px] font-semibold text-[#60738f]">최소 교신 횟수</span><select value={minCount} onChange={(event) => setMinCount(Number(event.target.value))} className="h-9 rounded-[8px] border border-[#d8e1ef] bg-white px-3 text-[12px]"><option value={1}>1회</option><option value={2}>2회</option><option value={3}>3회</option><option value={5}>5회</option><option value={10}>10회</option></select></label>
            <button type="button" disabled={busy} onClick={() => void loadMailCandidates()} className="om-btn-primary h-9 cursor-pointer rounded-[8px] px-4 text-[12px] disabled:opacity-60">불러오기</button>
          </>}
          <label><span className="mb-1.5 block text-[11px] font-semibold text-[#60738f]">한번에 그룹 설정</span><select value={groupName} onChange={(event) => setGroupName(event.target.value)} className="h-9 min-w-[150px] rounded-[8px] border border-[#d8e1ef] bg-white px-3 text-[12px]"><option value="">그룹 지정 안 함</option>{settings.groups.map((item) => <option key={item} value={item}>{item}</option>)}</select></label>
          <label><span className="mb-1.5 block text-[11px] font-semibold text-[#60738f]">중복 연락처</span><select value={duplicateMode} onChange={(event) => setDuplicateMode(event.target.value as "skip" | "update")} className="h-9 rounded-[8px] border border-[#d8e1ef] bg-white px-3 text-[12px]"><option value="skip">중복 제외</option><option value="update">기존 정보 보완</option></select></label>
        </div>
        <SelectionTable contacts={rows} selected={selected} setSelected={setSelected} showCount={mode === "mail"} />
        <div className="flex items-center justify-between px-5 py-4"><p className="text-[11px] text-[#7d8ba0]">선택 {selected.size.toLocaleString("ko-KR")}개 / 최대 5,000개</p><button type="button" disabled={busy || selected.size === 0} onClick={() => void importContacts(rows)} className="om-btn-primary h-10 cursor-pointer rounded-[9px] px-5 text-[13px] disabled:opacity-50">{busy ? "처리 중..." : "선택 연락처 저장"}</button></div>
      </> : null}

      {mode === "export" ? <div className="max-w-[850px] px-5 py-5">
        <div className="grid border-t border-[#e7edf7] text-[12px] sm:grid-cols-[170px_minmax(0,1fr)]"><div className="bg-[#fafbfd] px-4 py-4 font-semibold text-[#344767]">파일 형식</div><div className="flex flex-wrap gap-4 px-4 py-4">{[["csv", "CSV"], ["xlsx", "XLSX"], ["vcard", "vCard"]].map(([value, label]) => <label key={value} className="flex cursor-pointer items-center gap-2"><input type="radio" checked={format === value} onChange={() => setFormat(value as typeof format)} className="accent-[#2f6df6]" />{label}</label>)}</div></div>
        <div className="grid border-t border-[#e7edf7] text-[12px] sm:grid-cols-[170px_minmax(0,1fr)]"><div className="bg-[#fafbfd] px-4 py-4 font-semibold text-[#344767]">항목 선택</div><div className="flex flex-wrap gap-x-5 gap-y-3 px-4 py-4">{[["displayName", "이름"], ["email", "이메일"], ["phone", "전화번호"], ["companyName", "회사·소속"], ["groupName", "그룹"], ["memo", "메모"]].map(([value, label]) => <label key={value} className="flex cursor-pointer items-center gap-2"><input type="checkbox" disabled={value === "email"} checked={exportFields.has(value)} onChange={(event) => { const next = new Set(exportFields); if (event.target.checked) next.add(value); else next.delete(value); setExportFields(next); }} className="accent-[#2f6df6]" />{label}</label>)}</div></div>
        <div className="grid border-y border-[#e7edf7] text-[12px] sm:grid-cols-[170px_minmax(0,1fr)]"><div className="bg-[#fafbfd] px-4 py-4 font-semibold text-[#344767]">대상 선택</div><div className="space-y-3 px-4 py-4"><label className="flex cursor-pointer items-center gap-2"><input type="radio" checked={exportTarget === "all"} onChange={() => setExportTarget("all")} className="accent-[#2f6df6]" />전체 연락처 ({settings.contacts.length.toLocaleString("ko-KR")}개)</label><label className="flex cursor-pointer items-center gap-2"><input type="radio" checked={exportTarget === "selected"} disabled={selectedContacts.length === 0} onChange={() => setExportTarget("selected")} className="accent-[#2f6df6]" />목록에서 선택한 연락처 ({selectedContacts.length.toLocaleString("ko-KR")}개)</label><label className="flex flex-wrap items-center gap-2"><input type="radio" checked={exportTarget === "group"} disabled={settings.groups.length === 0} onChange={() => setExportTarget("group")} className="accent-[#2f6df6]" />그룹별 <select value={exportGroup} onChange={(event) => { setExportGroup(event.target.value); setExportTarget("group"); }} className="h-8 rounded-[7px] border border-[#d8e1ef] bg-white px-2"><option value="">그룹 선택</option>{settings.groups.map((item) => <option key={item} value={item}>{item}</option>)}</select></label></div></div>
        <div className="mt-5 flex justify-end"><button type="button" disabled={busy || (exportTarget === "group" && !exportGroup)} onClick={() => void exportContacts()} className="om-btn-primary h-10 cursor-pointer rounded-[9px] px-5 text-[13px] disabled:opacity-50">{busy ? "파일 생성 중..." : "파일로 저장하기"}</button></div>
      </div> : null}

      {mode === "duplicates" ? <div className="px-5 py-5"><div className="rounded-[10px] bg-[#f4f7fc] px-4 py-3 text-[12px] leading-5 text-[#60738f]">전화번호가 같거나 이름이 동일한 저장 연락처를 묶어 표시합니다. 병합하면 첫 번째 연락처의 이메일을 유지하고 비어 있는 이름·전화번호·회사·그룹·메모를 보완합니다.</div>{busy && duplicateGroups.length === 0 ? <div className="py-20 text-center text-[12px] text-[#8290a7]">중복 연락처를 확인하고 있습니다.</div> : duplicateGroups.length === 0 ? <div className="py-20 text-center"><p className="text-[14px] font-semibold text-[#344767]">정리할 중복 연락처가 없습니다.</p></div> : <div className="mt-4 space-y-3">{duplicateGroups.map((duplicate) => <div key={duplicate.key} className="flex flex-col gap-3 rounded-[12px] border border-[#e2e9f4] p-4 sm:flex-row sm:items-center sm:justify-between"><div className="min-w-0"><p className="text-[12px] font-semibold text-[#344767]">{duplicate.reason === "phone" ? "같은 전화번호" : "같은 이름"} · {duplicate.contacts.length}개</p><p className="mt-1 truncate text-[12px] text-[#74839b]">{duplicate.contacts.map((contact) => `${contact.displayName || "이름없음"} <${contact.email}>`).join(" · ")}</p></div><button type="button" disabled={busy} onClick={() => void mergeGroup(duplicate)} className="om-btn-secondary h-9 shrink-0 cursor-pointer rounded-[8px] px-4 text-[12px] disabled:opacity-50">병합</button></div>)}</div>}</div> : null}
    </div>
  );
}
