"use client";

import React, { useState, useEffect, useRef } from "react";
import dynamic from "next/dynamic";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/ui/dialog";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { toast } from "sonner";
import { Switch } from "@/components/ui/switch";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { cn } from "@/lib/utils";
import { ChevronsUpDown, Check } from "lucide-react";
import {
  ResizablePanelGroup,
  ResizablePanel,
  ResizableHandle,
} from "@/components/ui/resizable";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Mail,
  Inbox,
  RefreshCw,
  Plus,
  Settings,
  Trash2,
  Loader2,
  Search,
  ChevronRight,
  Paperclip,
  AlertCircle,
  CheckCircle,
  X,
  Reply,
  Forward,
  FolderOpen,
  Send,
  Download,
  Eye,
  EyeOff,
} from "lucide-react";
import DOMPurify from "isomorphic-dompurify";
import {
  getUserMailAccounts,
  createUserMailAccount,
  updateUserMailAccount,
  deleteUserMailAccount,
  testUserMailConnectionDirect,
  streamUserMails,
  getUserMailDetail,
  markUserMailAsRead,
  deleteUserMail,
  getUserMailFolders,
  moveUserMail,
  sendUserMail,
  getUserMailAttachments,
  downloadAttachment,
  streamFolderMails,
  UserMailAccount,
  ReceivedMail,
  MailDetail,
  CreateUserMailAccountDto,
  MailFolder,
  SendMailDto,

} from "@/lib/api/userMail";
import type ComposeDialogType from "./ComposeDialog";
const ComposeDialogDynamic = dynamic(() => import("./ComposeDialog"), { ssr: false }) as typeof ComposeDialogType;

const IMAP_PRESETS = [
  { label: "직접 입력", value: "custom", host: "", port: 993, useTls: true },
  { label: "Gmail", value: "gmail", host: "imap.gmail.com", port: 993, useTls: true },
  { label: "Naver", value: "naver", host: "imap.naver.com", port: 993, useTls: true },
  { label: "Outlook / Hotmail", value: "outlook", host: "outlook.office365.com", port: 993, useTls: true },
  { label: "Kakao", value: "kakao", host: "imap.kakao.com", port: 993, useTls: true },
  { label: "Daum", value: "daum", host: "imap.daum.net", port: 993, useTls: true },
];

const DEFAULT_FORM: CreateUserMailAccountDto = {
  displayName: "",
  email: "",
  protocol: "imap",
  host: "",
  port: 993,
  useTls: true,
  username: "",
  password: "",
};

export default function ImapMailPage() {
  const [accounts, setAccounts] = useState<UserMailAccount[]>([]);
  const [selectedAccount, setSelectedAccount] = useState<UserMailAccount | null>(null);
  const [mailsMap, setMailsMap] = useState<Map<number, ReceivedMail[]>>(new Map());
  const [loadingMap, setLoadingMap] = useState<Map<number, boolean>>(new Map());
  const [minSeqnoMap, setMinSeqnoMap] = useState<Map<number, number | null>>(new Map());
  const [loadingMoreMap, setLoadingMoreMap] = useState<Map<number, boolean>>(new Map());
  const [selectedMail, setSelectedMail] = useState<MailDetail | null>(null);
  const [downloadProgress, setDownloadProgress] = useState<Record<number, number>>({});
  const [loadingAccounts, setLoadingAccounts] = useState(false);
  const [loadingDetail, setLoadingDetail] = useState(false);
  const [showDialog, setShowDialog] = useState(false);
  const [editingAccount, setEditingAccount] = useState<UserMailAccount | null>(null);
  const [form, setForm] = useState<CreateUserMailAccountDto>(DEFAULT_FORM);
  const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
  const [testing, setTesting] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [formErrors, setFormErrors] = useState<Partial<Record<'displayName' | 'email' | 'host' | 'username' | 'password', string>>>({});

  // New states
  const [folders, setFolders] = useState<MailFolder[]>([]);
  const [currentFolder, setCurrentFolder] = useState<string>("INBOX");
  const [composeOpen, setComposeOpen] = useState(false);
  const [composeMode, setComposeMode] = useState<"new" | "reply" | "forward">("new");
  const [composeTo, setComposeTo] = useState("");
  const [composeCc, setComposeCc] = useState("");
  const [composeSubject, setComposeSubject] = useState("");
  const [composeInitialHtml, setComposeInitialHtml] = useState("");
  const [composeInReplyTo, setComposeInReplyTo] = useState("");
  const [composeReferences, setComposeReferences] = useState("");
  const [composeSending, setComposeSending] = useState(false);
  const [pendingDeleteMail, setPendingDeleteMail] = useState<ReceivedMail | null>(null);
  const [pendingDeleteAccount, setPendingDeleteAccount] = useState<UserMailAccount | null>(null);
  const [showPassword, setShowPassword] = useState(false);
  const [hostPopoverOpen, setHostPopoverOpen] = useState(false);

  const detailCacheRef = useRef<Map<string, MailDetail>>(new Map());
  const prefetchingRef = useRef<Set<string>>(new Set());
  const mailsMapRef = useRef<Map<number, ReceivedMail[]>>(new Map());
  const hoverTimerRef = useRef<NodeJS.Timeout | null>(null);

  // 현재 선택 계정 기준 파생값
  const mails = selectedAccount ? (mailsMap.get(selectedAccount.id) || []) : [];
  const loadingMails = selectedAccount ? (loadingMap.get(selectedAccount.id) ?? false) : false;
  const minSeqno = selectedAccount ? (minSeqnoMap.get(selectedAccount.id) ?? null) : null;
  const loadingMore = selectedAccount ? (loadingMoreMap.get(selectedAccount.id) ?? false) : false;

  const imapAccounts = accounts.filter((a) => a.protocol === "imap");

  useEffect(() => {
    loadAccounts();
  }, []);

  useEffect(() => {
    if (selectedAccount) {
      setSelectedMail(null);
      setCurrentFolder("INBOX");
      loadFolders(selectedAccount);
      // 아직 로딩 안 됐으면 시작
      if (!mailsMap.has(selectedAccount.id) && !loadingMap.get(selectedAccount.id)) {
        startStream(selectedAccount);
      }
    }
  }, [selectedAccount]);

  async function loadAccounts() {
    setLoadingAccounts(true);
    try {
      const data = await getUserMailAccounts();
      setAccounts(data);
      // 모든 계정 동시 프리로드
      const imapAccts = data.filter((a: UserMailAccount) => a.protocol === "imap");
      for (const account of imapAccts) {
        startStream(account);
      }
    } catch (e) {
      console.error("계정 목록 로드 실패:", e);
    } finally {
      setLoadingAccounts(false);
    }
  }

  async function loadFolders(account: UserMailAccount) {
    try {
      const data = await getUserMailFolders(account.id);
      setFolders(data);
    } catch {
      setFolders([]);
    }
  }

  async function prefetchDetail(account: UserMailAccount, mail: ReceivedMail) {
    if (detailCacheRef.current.has(mail.id)) return;
    if (prefetchingRef.current.has(mail.id)) return;
    prefetchingRef.current.add(mail.id);
    try {
      const seqno = parseInt(mail.id.split("-").pop() || "0");
      if (!seqno) return;
      const detail = await getUserMailDetail(account.id, seqno);
      if (detail) detailCacheRef.current.set(mail.id, detail);
    } catch {
      // 프리로드 실패 무시
    } finally {
      prefetchingRef.current.delete(mail.id);
    }
  }

  function startStream(account: UserMailAccount, before: number | null = null, append = false) {
    // 이미 로딩 중이면 스킵 (초기 로드 한정)
    if (!append && loadingMap.get(account.id)) return;

    setLoadingMap((prev) => new Map(prev).set(account.id, true));

    const cancel = streamUserMails(
      account.id, 20, before,
      (mail) => {
        setMailsMap((prev) => {
          const next = new Map(prev);
          const existing = next.get(account.id) || [];
          const updated = append
            ? [...existing, mail]
            : [mail, ...existing.filter((m) => m.id !== mail.id)];
          next.set(account.id, updated);
          mailsMapRef.current = next;
          return next;
        });
        setMinSeqnoMap((prev) => {
          const seqno = parseInt(mail.id.split("-").pop() || "0");
          const current = prev.get(account.id) ?? null;
          return new Map(prev).set(account.id, current === null ? seqno : Math.min(current, seqno));
        });
        setLoadingMap((prev) => new Map(prev).set(account.id, false));
      },
      () => {
        setLoadingMap((prev) => new Map(prev).set(account.id, false));
        setLoadingMoreMap((prev) => new Map(prev).set(account.id, false));
        // 상위 5개 자동 프리로드 (순차, Gmail은 throttling으로 느려지므로 간격 늘림)
        const currentMails = mailsMapRef.current.get(account.id) || [];
        const top5 = currentMails.slice(0, 5);
        const isGmail = account.host.toLowerCase().includes('gmail') || account.email.toLowerCase().includes('@gmail');
        const interval = isGmail ? 800 : 100;
        top5.forEach((m, i) => {
          setTimeout(() => prefetchDetail(account, m), i * interval);
        });
      },
      (err) => {
        setLoadingMap((prev) => new Map(prev).set(account.id, false));
        setLoadingMoreMap((prev) => new Map(prev).set(account.id, false));
        console.error("스트리밍 오류:", err);
      }
    );
    return cancel;
  }

  function handleFolderClick(folder: string) {
    if (!selectedAccount) return;
    setCurrentFolder(folder);
    setSelectedMail(null);

    if (folder === "INBOX") {
      setMailsMap((prev) => { const n = new Map(prev); n.delete(selectedAccount.id); return n; });
      setMinSeqnoMap((prev) => { const n = new Map(prev); n.delete(selectedAccount.id); return n; });
      startStream(selectedAccount);
    } else {
      setMailsMap((prev) => { const n = new Map(prev); n.set(selectedAccount.id, []); return n; });
      setLoadingMap((prev) => new Map(prev).set(selectedAccount.id, true));
      streamFolderMails(
        selectedAccount.id, folder, 20, null,
        (mail) => {
          setMailsMap((prev) => {
            const n = new Map(prev);
            n.set(selectedAccount.id, [...(n.get(selectedAccount.id) || []), mail]);
            return n;
          });
          setLoadingMap((prev) => new Map(prev).set(selectedAccount.id, false));
        },
        () => setLoadingMap((prev) => new Map(prev).set(selectedAccount.id, false)),
        (err) => { setLoadingMap((prev) => new Map(prev).set(selectedAccount.id, false)); console.error(err); }
      );
    }
  }

  async function handleMailClick(mail: ReceivedMail) {
    if (!selectedAccount) return;
    const seqno = parseInt(mail.id.split("-").pop() || "0");

    // 캐시 히트 시 즉시 표시
    const cached = detailCacheRef.current.get(mail.id);
    if (cached) {
      setSelectedMail(cached);
      // 첨부파일 로드
      if (seqno) {
      }
      if (!mail.isRead) {
        markUserMailAsRead(selectedAccount.id, seqno).then(() => loadFolders(selectedAccount)).catch(() => {});
        setMailsMap((prev) => {
          const next = new Map(prev);
          const mails = (next.get(selectedAccount.id) || []).map((m) =>
            m.id === mail.id ? { ...m, isRead: true } : m
          );
          next.set(selectedAccount.id, mails);
          mailsMapRef.current = next;
          return next;
        });
      }
      return;
    }

    // 캐시 미스 시 fetch
    setLoadingDetail(true);
    try {
      const detail = await getUserMailDetail(selectedAccount.id, seqno);
      if (detail) {
        detailCacheRef.current.set(mail.id, detail);
        setSelectedMail(detail);
      }
      // 첨부파일 로드
      if (seqno) {
      }
      if (!mail.isRead) {
        await markUserMailAsRead(selectedAccount.id, seqno);
        setMailsMap((prev) => {
          const next = new Map(prev);
          const mails = (next.get(selectedAccount.id) || []).map((m) =>
            m.id === mail.id ? { ...m, isRead: true } : m
          );
          next.set(selectedAccount.id, mails);
          mailsMapRef.current = next;
          return next;
        });
        loadFolders(selectedAccount);
      }
    } catch (e) {
      console.error("메일 상세 로드 실패:", e);
    } finally {
      setLoadingDetail(false);
    }
  }

  async function handleDeleteMail(mail: ReceivedMail) {
    if (!selectedAccount) return;
    setPendingDeleteMail(mail);
  }

  async function confirmDeleteMail() {
    if (!selectedAccount || !pendingDeleteMail) return;
    const mail = pendingDeleteMail;
    setPendingDeleteMail(null);
    const seqno = parseInt(mail.id.split("-").pop() || "0");
    try {
      await deleteUserMail(selectedAccount.id, seqno);
      setMailsMap((prev) => {
        const next = new Map(prev);
        const existing = next.get(selectedAccount.id) || [];
        next.set(selectedAccount.id, existing.filter((m) => m.id !== mail.id));
        return next;
      });
      if (selectedMail?.id === mail.id) setSelectedMail(null);
      loadFolders(selectedAccount);
    } catch (e: any) {
      toast.error("메일 삭제 실패: " + e.message);
    }
  }

  async function handleMove(mail: ReceivedMail, targetFolder: string) {
    if (!selectedAccount) return;
    const seqno = parseInt(mail.id.split("-").pop() || "0");
    try {
      await moveUserMail(selectedAccount.id, seqno, targetFolder);
      setMailsMap((prev) => {
        const next = new Map(prev);
        next.set(selectedAccount.id, (next.get(selectedAccount.id) || []).filter((m) => m.id !== mail.id));
        return next;
      });
      if (selectedMail?.id === mail.id) setSelectedMail(null);
    } catch (e) {
      console.error("메일 이동 실패:", e);
    }
  }

  function handleReply() {
    if (!selectedMail) return;
    setComposeMode("reply");
    setComposeTo(selectedMail.from);
    setComposeSubject(`Re: ${selectedMail.subject.replace(/^Re:\s*/i, "")}`);
    setComposeInReplyTo(selectedMail.messageId);
    setComposeReferences(selectedMail.messageId);
    const dateStr = new Date(selectedMail.date).toLocaleString("ko-KR");
    setComposeInitialHtml(
      `<br><br><div style="border-left:2px solid #ccc;padding-left:8px;color:#666">
        <div>${dateStr}, ${selectedMail.from} 작성:</div>
        <blockquote>${selectedMail.htmlBody || selectedMail.textBody}</blockquote>
      </div>`
    );
    setComposeOpen(true);
  }

  function handleForward() {
    if (!selectedMail) return;
    setComposeMode("forward");
    setComposeTo("");
    setComposeSubject(`Fwd: ${selectedMail.subject.replace(/^Fwd:\s*/i, "")}`);
    setComposeInReplyTo("");
    setComposeReferences("");
    setComposeInitialHtml(
      `<br><br><div>---------- 전달된 메일 ----------</div>
       <div>보낸사람: ${selectedMail.from}</div>
       <div>날짜: ${new Date(selectedMail.date).toLocaleString("ko-KR")}</div>
       <div>제목: ${selectedMail.subject}</div>
       <div>받는사람: ${selectedMail.to}</div>
       <br>${selectedMail.htmlBody || selectedMail.textBody}`
    );
    setComposeOpen(true);
  }

  function openAddDialog() {
    setEditingAccount(null);
    setForm(DEFAULT_FORM);
    setTestResult(null);
    setShowPassword(false);
    setHostPopoverOpen(false);
    setFormErrors({});
    setShowDialog(true);
  }

  function openEditDialog(account: UserMailAccount) {
    setEditingAccount(account);
    setForm({
      displayName: account.displayName,
      email: account.email,
      protocol: "imap",
      host: account.host,
      port: account.port,
      useTls: account.useTls,
      username: account.username,
      password: "",
    });
    setTestResult(null);
    setShowPassword(false);
    setShowDialog(true);
  }

  function handleTlsToggle(checked: boolean) {
    setForm((prev) => ({
      ...prev,
      useTls: checked,
      port: checked ? 993 : 143,
    }));
  }

  async function handleSave() {
    const errors: typeof formErrors = {};
    if (!form.displayName.trim()) errors.displayName = "표시 이름을 입력하세요.";
    if (!form.email.trim()) errors.email = "이메일 주소를 입력하세요.";
    if (!form.host.trim()) errors.host = "IMAP 호스트를 입력하세요.";
    if (!form.username.trim()) errors.username = "사용자명을 입력하세요.";
    if (!editingAccount && !form.password.trim()) errors.password = "비밀번호를 입력하세요.";
    if (Object.keys(errors).length > 0) { setFormErrors(errors); return; }
    setFormErrors({});
    setSaving(true);
    setSaveError(null);
    try {
      if (editingAccount) {
        await updateUserMailAccount(editingAccount.id, form);
      } else {
        await createUserMailAccount(form);
      }
      await loadAccounts();
      setShowDialog(false);
    } catch (e: any) {
      const msg = e?.response?.data?.message || (e instanceof Error ? e.message : "저장 실패");
      setSaveError(msg);
    } finally {
      setSaving(false);
    }
  }

  async function handleDeleteAccount(account: UserMailAccount) {
    setPendingDeleteAccount(account);
  }

  async function confirmDeleteAccount() {
    if (!pendingDeleteAccount) return;
    const account = pendingDeleteAccount;
    setPendingDeleteAccount(null);
    try {
      await deleteUserMailAccount(account.id);
      if (selectedAccount?.id === account.id) {
        setSelectedAccount(null);
        setSelectedMail(null);
      }
      setMailsMap((prev) => { const next = new Map(prev); next.delete(account.id); return next; });
      setMinSeqnoMap((prev) => { const next = new Map(prev); next.delete(account.id); return next; });
      setLoadingMap((prev) => { const next = new Map(prev); next.delete(account.id); return next; });
      setLoadingMoreMap((prev) => { const next = new Map(prev); next.delete(account.id); return next; });
      await loadAccounts();
    } catch (e) {
      console.error("계정 삭제 실패:", e);
    }
  }

  async function handleTest() {
    setTesting(true);
    setTestResult(null);
    try {
      const result = await testUserMailConnectionDirect({
        protocol: form.protocol,
        host: form.host,
        port: form.port,
        useTls: form.useTls,
        username: form.username,
        password: form.password,
      });
      setTestResult(result);
    } catch (e: unknown) {
      setTestResult({
        success: false,
        message: e instanceof Error ? e.message : "연결 테스트 실패",
      });
    } finally {
      setTesting(false);
    }
  }

  const filteredMails = mails.filter(
    (m) =>
      m.subject.toLowerCase().includes(searchTerm.toLowerCase()) ||
      m.from.toLowerCase().includes(searchTerm.toLowerCase())
  );

  function formatDate(dateStr: string) {
    const d = new Date(dateStr);
    const now = new Date();
    const isToday =
      d.getFullYear() === now.getFullYear() &&
      d.getMonth() === now.getMonth() &&
      d.getDate() === now.getDate();
    return isToday
      ? d.toLocaleTimeString("ko-KR", { hour: "2-digit", minute: "2-digit" })
      : d.toLocaleDateString("ko-KR", { month: "short", day: "numeric" });
  }

  return (
    <div className="flex flex-col h-full">
      {/* 헤더 */}
      <div className="flex items-center justify-between px-4 py-3 border-b">
        <div className="flex items-center gap-2">
          <Mail className="h-5 w-5 text-muted-foreground" />
          <h1 className="text-lg font-semibold">메일 관리</h1>
        </div>
        <div className="flex items-center gap-2">
          <Button size="sm" onClick={() => { setComposeMode("new"); setComposeInitialHtml(""); setComposeTo(""); setComposeCc(""); setComposeSubject(""); setComposeOpen(true); }}>
            <Plus className="h-4 w-4 mr-1" />
            작성
          </Button>
        </div>
      </div>

      {/* 3단 패널 */}
      <div className="flex-1 overflow-hidden">
        <ResizablePanelGroup direction="horizontal" className="h-full">
          {/* 계정 목록 */}
          <ResizablePanel defaultSize={18} minSize={14}>
            <div className="flex flex-col h-full border-r">
              <div className="px-3 py-2 border-b text-xs font-medium text-muted-foreground flex items-center gap-1">
                <Inbox className="h-3.5 w-3.5" />
                계정 목록
                {loadingAccounts && <Loader2 className="h-3 w-3 animate-spin" />}
                <button
                  className="ml-auto p-0.5 hover:text-foreground text-muted-foreground"
                  onClick={openAddDialog}
                  title="계정 추가"
                >
                  <Plus className="h-3.5 w-3.5" />
                </button>
              </div>
              <div className="flex-1 overflow-y-auto">
                {imapAccounts.length === 0 && !loadingAccounts ? (
                  <div className="p-3 text-xs text-muted-foreground text-center">
                    계정이 없습니다
                  </div>
                ) : (
                  imapAccounts.map((account) => (
                    <div
                      key={account.id}
                      className={`group flex items-center gap-2 px-3 py-2.5 cursor-pointer hover:bg-muted/50 border-b text-sm transition-colors ${
                        selectedAccount?.id === account.id ? "bg-muted" : ""
                      }`}
                      onClick={() => setSelectedAccount(account)}
                    >
                      <div className="flex-1 min-w-0">
                        <div className="font-medium truncate">{account.displayName}</div>
                        <div className="text-xs text-muted-foreground truncate">{account.email}</div>
                      </div>
                      <div className="flex gap-1 opacity-0 group-hover:opacity-100">
                        <button
                          className="p-0.5 hover:text-foreground text-muted-foreground"
                          onClick={(e) => { e.stopPropagation(); openEditDialog(account); }}
                        >
                          <Settings className="h-3.5 w-3.5" />
                        </button>
                        <button
                          className="p-0.5 hover:text-destructive text-muted-foreground"
                          onClick={(e) => { e.stopPropagation(); handleDeleteAccount(account); }}
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </button>
                      </div>
                    </div>
                  ))
                )}
                {/* 폴더 목록 */}
                {selectedAccount && folders.length > 0 && (
                  <div className="mt-4">
                    <div className="text-xs font-semibold text-muted-foreground px-2 mb-1 flex items-center gap-1">
                      <FolderOpen className="w-3 h-3" /> 폴더
                    </div>
                    {folders.map((folder) => (
                      <div
                        key={folder.path}
                        className={`px-2 py-1 text-sm cursor-pointer rounded hover:bg-accent flex justify-between items-center ${currentFolder === folder.path ? "bg-accent font-medium" : ""}`}
                        onClick={() => handleFolderClick(folder.path)}
                      >
                        <span>{folder.name}</span>
                        {folder.unseen > 0 && <Badge variant="secondary" className="text-xs">{folder.unseen}</Badge>}
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </div>
          </ResizablePanel>

          <ResizableHandle />

          {/* 메일 목록 */}
          <ResizablePanel defaultSize={32} minSize={22}>
            <div className="flex flex-col h-full border-r">
              <div className="px-3 py-2 border-b flex items-center gap-2">
                <div className="relative flex-1">
                  <Search className="absolute left-2 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" />
                  <Input
                    className="pl-7 h-7 text-xs"
                    placeholder="제목, 발신자 검색"
                    value={searchTerm}
                    onChange={(e) => setSearchTerm(e.target.value)}
                  />
                </div>
                {selectedAccount && (
                  <button
                    className="text-muted-foreground hover:text-foreground"
                    onClick={() => {
                      if (selectedAccount) {
                        setMailsMap((prev) => { const next = new Map(prev); next.delete(selectedAccount.id); return next; });
                        setMinSeqnoMap((prev) => { const next = new Map(prev); next.delete(selectedAccount.id); return next; });
                        if (currentFolder === "INBOX") {
                          startStream(selectedAccount);
                        } else {
                          handleFolderClick(currentFolder);
                        }
                      }
                    }}
                  >
                    <RefreshCw className="h-3.5 w-3.5" />
                  </button>
                )}
              </div>
              <div className="flex-1 overflow-y-auto">
                {!selectedAccount ? (
                  <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                    <Mail className="h-8 w-8 opacity-30" />
                    <p className="text-sm">계정을 선택하세요</p>
                  </div>
                ) : loadingMails && mails.length === 0 ? (
                  <div className="flex items-center justify-center h-full">
                    <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                  </div>
                ) : filteredMails.length === 0 ? (
                  <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                    <Inbox className="h-8 w-8 opacity-30" />
                    <p className="text-sm">{searchTerm ? `"${searchTerm}" 검색 결과가 없습니다` : "메일이 없습니다"}</p>
                  </div>
                ) : (
                  <>
                    {filteredMails.map((mail) => (
                      <div
                        key={mail.id}
                        className={`group flex items-start gap-2 px-3 py-2.5 cursor-pointer hover:bg-muted/50 border-b transition-colors ${
                          selectedMail?.id === mail.id ? "bg-muted" : ""
                        }`}
                        onClick={() => handleMailClick(mail)}
                        onMouseEnter={() => {
                          if (!selectedAccount || detailCacheRef.current.has(mail.id)) return;
                          hoverTimerRef.current = setTimeout(() => {
                            prefetchDetail(selectedAccount, mail);
                          }, 300);
                        }}
                        onMouseLeave={() => {
                          if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
                        }}
                      >
                        <div className="mt-1">
                          {!mail.isRead ? (
                            <div className="h-2 w-2 rounded-full bg-blue-500" />
                          ) : (
                            <div className="h-2 w-2 rounded-full bg-transparent border border-muted-foreground/30" />
                          )}
                        </div>
                        <div className="flex-1 min-w-0">
                          <div className="flex items-center justify-between gap-1">
                            <span className={`text-xs truncate ${!mail.isRead ? "font-semibold" : "text-muted-foreground"}`}>
                              {mail.from}
                            </span>
                            <span className="text-xs text-muted-foreground shrink-0">
                              {formatDate(mail.date)}
                            </span>
                          </div>
                          <div className={`text-sm truncate ${!mail.isRead ? "font-medium" : ""}`}>
                            {mail.subject || "(제목 없음)"}
                          </div>
                          <div className="flex items-center gap-1 mt-0.5">
                            <span className="text-xs text-muted-foreground truncate flex-1">
                              {mail.preview}
                            </span>
                            {mail.hasAttachments && (
                              <Paperclip className="h-3 w-3 text-muted-foreground shrink-0" />
                            )}
                          </div>
                        </div>
                        <button
                          className="opacity-0 group-hover:opacity-100 p-0.5 hover:text-destructive text-muted-foreground mt-1"
                          onClick={(e) => { e.stopPropagation(); handleDeleteMail(mail); }}
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </button>
                      </div>
                    ))}
                    {loadingMore ? (
                      <div className="flex items-center justify-center py-3">
                        <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
                      </div>
                    ) : !loadingMore && mails.length >= 20 ? (
                      <button
                        className="w-full py-2 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors"
                        onClick={() => {
                          if (selectedAccount) {
                            setLoadingMoreMap((prev) => new Map(prev).set(selectedAccount.id, true));
                            startStream(selectedAccount, minSeqno, true);
                          }
                        }}
                      >
                        이전 메일 더 보기
                      </button>
                    ) : null}
                  </>
                )}
              </div>
            </div>
          </ResizablePanel>

          <ResizableHandle />

          {/* 메일 상세 */}
          <ResizablePanel defaultSize={50} minSize={30}>
            <div className="flex flex-col h-full">
              {loadingDetail ? (
                <div className="flex items-center justify-center h-full">
                  <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                </div>
              ) : !selectedMail ? (
                <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-2">
                  <ChevronRight className="h-8 w-8 opacity-30" />
                  <p className="text-sm">메일을 선택하세요</p>
                </div>
              ) : (
                <>
                  <div className="px-4 py-3 border-b space-y-1">
                    <h2 className="font-semibold text-base">
                      {selectedMail.subject || "(제목 없음)"}
                    </h2>
                    <div className="text-xs text-muted-foreground space-y-0.5">
                      <div><span className="font-medium">From:</span> {selectedMail.from}</div>
                      <div><span className="font-medium">To:</span> {selectedMail.to}</div>
                      {selectedMail.cc && (
                        <div><span className="font-medium">CC:</span> {selectedMail.cc}</div>
                      )}
                      <div><span className="font-medium">Date:</span> {new Date(selectedMail.date).toLocaleString("ko-KR")}</div>
                    </div>
                    {selectedMail.attachments.length > 0 && (
                      <div className="flex flex-wrap gap-1 pt-1">
                        {selectedMail.attachments.map((att, i) => {
                          const seqno = selectedMail ? parseInt(selectedMail.id.split("-").pop() || "0") : 0;
                          const accountId = selectedAccount?.id || 0;
                          const progress = downloadProgress[i];
                          const isDownloading = progress !== undefined;
                          return (
                            <button key={i}
                              disabled={isDownloading}
                              onClick={async () => {
                                setDownloadProgress(p => ({ ...p, [i]: 0 }));
                                try {
                                  const list = await getUserMailAttachments(accountId, seqno, currentFolder);
                                  const matched = list.find(a => a.filename === att.filename) || list[i];
                                  if (!matched) { toast.error('첨부파일 정보를 불러올 수 없습니다'); return; }
                                  await downloadAttachment(
                                    accountId, seqno, matched.partId, matched.filename, currentFolder,
                                    (pct) => setDownloadProgress(p => ({ ...p, [i]: pct })),
                                    matched.size
                                  );
                                } catch (e: any) { toast.error(e.message); }
                                finally { setDownloadProgress(p => { const next = { ...p }; delete next[i]; return next; }); }
                              }}
                              className="relative inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-secondary hover:bg-accent border disabled:opacity-60 disabled:cursor-not-allowed cursor-pointer min-w-[80px] overflow-hidden">
                              {isDownloading ? (
                                <>
                                  <Loader2 className="h-3 w-3 animate-spin shrink-0" />
                                  <span className="flex-1 truncate">{att.filename}</span>
                                  <span className="shrink-0 font-mono">{progress}%</span>
                                  <span className="absolute inset-x-0 bottom-0 h-0.5 rounded-full bg-primary/30 overflow-hidden">
                                    <span className="block h-full bg-primary transition-all duration-200" style={{ width: `${progress}%` }} />
                                  </span>
                                </>
                              ) : (
                                <>
                                  <Download className="h-3 w-3 shrink-0" />
                                  <span className="truncate">{att.filename}</span>
                                </>
                              )}
                            </button>
                          );
                        })}
                      </div>
                    )}
                    {/* 답장/전달/이동/삭제 버튼 */}
                    <div className="flex gap-2 mt-2 flex-wrap">
                      <Button size="sm" variant="outline" onClick={handleReply}>
                        <Reply className="w-3 h-3 mr-1" /> 답장
                      </Button>
                      <Button size="sm" variant="outline" onClick={handleForward}>
                        <Forward className="w-3 h-3 mr-1" /> 전달
                      </Button>
                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button size="sm" variant="outline">
                            <FolderOpen className="w-3 h-3 mr-1" /> 이동
                          </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent>
                          {folders.filter((f) => f.path !== currentFolder).map((f) => (
                            <DropdownMenuItem key={f.path} onClick={() => handleMove(selectedMail, f.path)}>
                              {f.name}
                            </DropdownMenuItem>
                          ))}
                        </DropdownMenuContent>
                      </DropdownMenu>
                      <Button size="sm" variant="destructive" onClick={() => handleDeleteMail(selectedMail)}>
                        <Trash2 className="w-3 h-3 mr-1" /> 삭제
                      </Button>
                    </div>
                  </div>
                  <div className="flex-1 overflow-hidden">
                    {selectedMail.htmlBody ? (
                      <iframe
                        srcDoc={DOMPurify.sanitize(selectedMail.htmlBody)}
                        className="w-full h-full border-0"
                        sandbox="allow-same-origin"
                        title="메일 본문"
                      />
                    ) : (
                      <div className="p-4 overflow-y-auto h-full">
                        <pre className="text-sm whitespace-pre-wrap font-sans">
                          {selectedMail.textBody}
                        </pre>
                      </div>
                    )}
                  </div>
                </>
              )}
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>

      {/* ComposeDialog */}
      <ComposeDialogDynamic
        open={composeOpen}
        onOpenChange={setComposeOpen}
        mode={composeMode}
        to={composeTo} setTo={setComposeTo}
        cc={composeCc} setCc={setComposeCc}
        subject={composeSubject} setSubject={setComposeSubject}
        initialHtml={composeInitialHtml} setInitialHtml={setComposeInitialHtml}
        inReplyTo={composeInReplyTo}
        references={composeReferences}
        sending={composeSending} setSending={setComposeSending}
        accountId={selectedAccount?.id ?? null}
        accounts={imapAccounts}
      />

      {/* 계정 추가/편집 다이얼로그 */}
      <Dialog open={showDialog} onOpenChange={setShowDialog}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>
              {editingAccount ? "IMAP 계정 편집" : "IMAP 계정 추가"}
            </DialogTitle>
          </DialogHeader>
          <div className="space-y-3 py-2">
            <div className="space-y-1">
              <Label className="text-xs">표시 이름</Label>
              <Input
                value={form.displayName}
                onChange={(e) => { setForm((p) => ({ ...p, displayName: e.target.value })); setFormErrors((p) => ({ ...p, displayName: undefined })); }}
                placeholder="내 Gmail"
                className={formErrors.displayName ? "border-destructive" : ""}
              />
              {formErrors.displayName && <p className="text-xs text-destructive">{formErrors.displayName}</p>}
            </div>
            <div className="space-y-1">
              <Label className="text-xs">이메일 주소</Label>
              <Input
                type="email"
                value={form.email}
                onChange={(e) => { setForm((p) => ({ ...p, email: e.target.value, username: e.target.value })); setFormErrors((p) => ({ ...p, email: undefined })); }}
                placeholder="user@example.com"
                className={formErrors.email ? "border-destructive" : ""}
              />
              {formErrors.email && <p className="text-xs text-destructive">{formErrors.email}</p>}
            </div>
            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1">
                <Label className="text-xs">IMAP 호스트</Label>
                <Popover open={hostPopoverOpen} onOpenChange={setHostPopoverOpen}>
                  <PopoverTrigger asChild>
                    <Button variant="outline" role="combobox" className="w-full justify-between font-normal">
                      <span className={cn("truncate", !form.host && "text-muted-foreground")}>
                        {form.host || "imap.gmail.com"}
                      </span>
                      <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent className="w-[220px] p-0 z-[10002]" align="start">
                    <Command>
                      <CommandInput
                        placeholder="호스트 직접 입력..."
                        value={form.host}
                        onValueChange={(v) => { setForm((p) => ({ ...p, host: v })); setFormErrors((p) => ({ ...p, host: undefined })); }}
                      />
                      <CommandList>
                        <CommandEmpty>직접 입력한 값을 사용합니다</CommandEmpty>
                        <CommandGroup>
                          {IMAP_PRESETS.filter((p) => p.value !== "custom").map((preset) => (
                            <CommandItem
                              key={preset.value}
                              value={preset.host}
                              onSelect={() => {
                                setForm((p) => ({ ...p, host: preset.host, port: preset.port, useTls: preset.useTls }));
                                setHostPopoverOpen(false);
                              }}
                            >
                              <Check className={cn("mr-2 h-4 w-4", form.host === preset.host ? "opacity-100" : "opacity-0")} />
                              <div>
                                <div className="text-sm font-medium">{preset.label}</div>
                                <div className="text-xs text-muted-foreground">{preset.host}</div>
                              </div>
                            </CommandItem>
                          ))}
                        </CommandGroup>
                      </CommandList>
                    </Command>
                  </PopoverContent>
                </Popover>
              {formErrors.host && <p className="text-xs text-destructive">{formErrors.host}</p>}
              </div>
              <div className="space-y-1">
                <Label className="text-xs">포트</Label>
                <Input
                  type="number"
                  value={form.port}
                  onChange={(e) => setForm((p) => ({ ...p, port: parseInt(e.target.value) || 993 }))}
                />
              </div>
            </div>
            <div className="flex items-center justify-between">
              <Label className="text-xs">TLS/SSL 사용</Label>
              <Switch checked={form.useTls} onCheckedChange={handleTlsToggle} />
            </div>
            <div className="space-y-1">
              <Label className="text-xs">사용자명</Label>
              <Input
                value={form.username}
                onChange={(e) => { setForm((p) => ({ ...p, username: e.target.value })); setFormErrors((p) => ({ ...p, username: undefined })); }}
                placeholder="user@example.com"
                className={formErrors.username ? "border-destructive" : ""}
              />
              {formErrors.username && <p className="text-xs text-destructive">{formErrors.username}</p>}
            </div>
            <div className="space-y-1">
              <Label className="text-xs">비밀번호 {editingAccount && "(변경 시에만 입력)"}</Label>
              <div className="relative">
                <Input
                  type={showPassword ? "text" : "password"}
                  value={form.password}
                  onChange={(e) => { setForm((p) => ({ ...p, password: e.target.value })); setFormErrors((p) => ({ ...p, password: undefined })); }}
                  onKeyDown={(e) => { if (e.key === "Enter") handleSave(); }}
                  placeholder="••••••••"
                  className={`pr-9 ${formErrors.password ? "border-destructive" : ""}`}
                />
                <button
                  type="button"
                  className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                  onClick={() => setShowPassword((v) => !v)}
                >
                  {showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
                </button>
              </div>
              {formErrors.password && <p className="text-xs text-destructive">{formErrors.password}</p>}
            </div>
            {editingAccount && (
              <div>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={handleTest}
                  disabled={testing}
                >
                  {testing ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin mr-1" />
                  ) : null}
                  연결 테스트
                </Button>
                {testResult && (
                  <div className={`mt-2 text-xs flex items-center gap-1 ${testResult.success ? "text-green-600" : "text-red-600"}`}>
                    {testResult.success ? (
                      <CheckCircle className="h-3.5 w-3.5" />
                    ) : (
                      <AlertCircle className="h-3.5 w-3.5" />
                    )}
                    {testResult.message}
                  </div>
                )}
              </div>
            )}
          </div>
          {saveError && (
            <div className="px-6 pb-2 text-sm text-red-600">{saveError}</div>
          )}
          <DialogFooter>
            <Button variant="outline" onClick={() => setShowDialog(false)}>
              <X className="h-4 w-4 mr-1" />
              취소
            </Button>
            <Button onClick={handleSave} disabled={saving}>
              {saving && <Loader2 className="h-4 w-4 animate-spin mr-1" />}
              저장
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 메일 삭제 확인 */}
      <AlertDialog open={!!pendingDeleteMail} onOpenChange={(open) => { if (!open) setPendingDeleteMail(null); }}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>메일 삭제</AlertDialogTitle>
            <AlertDialogDescription>메일을 삭제하시겠습니까?</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>취소</AlertDialogCancel>
            <AlertDialogAction onClick={confirmDeleteMail} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">삭제</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 계정 삭제 확인 */}
      <AlertDialog open={!!pendingDeleteAccount} onOpenChange={(open) => { if (!open) setPendingDeleteAccount(null); }}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>계정 삭제</AlertDialogTitle>
            <AlertDialogDescription>"{pendingDeleteAccount?.displayName}" 계정을 삭제하시겠습니까?</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>취소</AlertDialogCancel>
            <AlertDialogAction onClick={confirmDeleteAccount} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">삭제</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  );
}
