import { useMutation, useQuery } from "@tanstack/react-query";
import {
  AlertCircle,
  CheckCircle2,
  Download,
  FileText,
  Loader2,
  Upload,
} from "lucide-react";
import * as React from "react";
import { Button } from "../../../components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "../../../components/ui/dialog";
import { ScrollArea } from "../../../components/ui/scroll-area";
import {
  type BulkUserItem,
  type BulkUserResult,
  bulkCreateUsers,
  createTenant,
  fetchTenants,
  fetchUsers,
} from "../../../lib/adminApi";
import { t } from "../../../lib/i18n";
import {
  type TenantCSVRow,
  type TenantImportPreviewRow,
  buildTenantImportPreview,
} from "../../tenants/utils/tenantCsvImport";
import { isHanmacFamilyTenant, isHanmacFamilyUser } from "../orgChartPicker";
import { parseUserCSV } from "../utils/csvParser";
import {
  type HanmacImportEmailPreview,
  buildHanmacImportEmailPreview,
} from "../utils/hanmacImportEmail";

interface UserBulkUploadModalProps {
  onSuccess?: () => void;
}

function buildUserTenantPreviewRows(
  users: BulkUserItem[],
  tenants: Parameters<typeof buildTenantImportPreview>[1],
) {
  const rowsByKey = new Map<string, TenantCSVRow>();

  users.forEach((user, index) => {
    const key = tenantImportKeyFromUser(user);
    if (!key || rowsByKey.has(key)) {
      return;
    }

    rowsByKey.set(key, {
      rowNumber: index + 2,
      tenantId: user.tenantImport?.sourceTenantId ?? "",
      name: user.tenantImport?.name || user.tenantSlug || key,
      type: user.tenantImport?.type || "COMPANY",
      parentTenantId: user.tenantImport?.parentTenantId ?? "",
      parentTenantSlug: user.tenantImport?.parentTenantSlug ?? "",
      slug: user.tenantImport?.slug || user.tenantSlug || key,
      memo: user.tenantImport?.memo ?? "",
      emailDomain: user.tenantImport?.emailDomain ?? "",
      visibility: "public",
      orgUnitType: "node",
    });
  });

  return buildTenantImportPreview([...rowsByKey.values()], tenants);
}

function tenantImportKeyFromUser(user: BulkUserItem) {
  return (
    user.tenantImport?.sourceTenantId ||
    user.tenantImport?.slug ||
    user.tenantSlug ||
    user.tenantImport?.name ||
    ""
  );
}

function tenantImportKeyFromRow(row: TenantCSVRow) {
  return row.tenantId || row.slug || row.name;
}

function splitTenantImportDomains(value: string) {
  return value
    .replaceAll("\n", ";")
    .replaceAll(",", ";")
    .split(";")
    .map((domain) => domain.trim().toLowerCase())
    .filter(Boolean);
}

function emailLocalPart(email: string) {
  return email.trim().toLowerCase().split("@")[0] || "";
}

function hanmacEmailStatusLabel(preview?: HanmacImportEmailPreview) {
  if (!preview) return "";
  if (preview.status === "suggested") return "제안";
  if (preview.status === "needsReview") return "확인 필요";
  if (preview.status === "ruleMismatch") return "규칙 확인";
  if (preview.status === "blockingError") return "오류";
  return "";
}

function hanmacEmailStatusClass(preview?: HanmacImportEmailPreview) {
  if (!preview) return "text-muted-foreground";
  if (preview.status === "blockingError") return "text-destructive";
  if (preview.status === "ruleMismatch" || preview.status === "needsReview") {
    return "text-amber-600";
  }
  if (preview.status === "suggested") return "text-blue-600";
  return "text-muted-foreground";
}

export function UserBulkUploadModal({ onSuccess }: UserBulkUploadModalProps) {
  const [open, setOpen] = React.useState(false);
  const [file, setFile] = React.useState<File | null>(null);
  const [parsing, setParsing] = React.useState(false);
  const [previewData, setPreviewData] = React.useState<BulkUserItem[]>([]);
  const [tenantPreviewRows, setTenantPreviewRows] = React.useState<
    TenantImportPreviewRow[]
  >([]);
  const [selectedTenantMatches, setSelectedTenantMatches] = React.useState<
    Record<number, string>
  >({});
  const [selectedTenantCreateSlugs, setSelectedTenantCreateSlugs] =
    React.useState<Record<number, string>>({});
  const [results, setResults] = React.useState<BulkUserResult[] | null>(null);
  const [preparing, setPreparing] = React.useState(false);
  const fileInputRef = React.useRef<HTMLInputElement>(null);

  const tenantQuery = useQuery({
    queryKey: ["tenants", "user-bulk-import"],
    queryFn: () => fetchTenants(1000, 0),
  });

  const usersQuery = useQuery({
    queryKey: ["users", "user-bulk-import-email-policy"],
    queryFn: () => fetchUsers(10000, 0),
    enabled: open,
  });

  const mutation = useMutation({
    mutationFn: bulkCreateUsers,
    onSuccess: (data) => {
      setResults(data.results);
      onSuccess?.();
    },
  });

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = e.target.files?.[0];
    if (selectedFile) {
      setFile(selectedFile);
      parseCSV(selectedFile);
    }
  };

  const parseCSV = (file: File) => {
    setParsing(true);
    const reader = new FileReader();
    reader.onload = (e) => {
      const text = e.target?.result as string;
      const data = parseUserCSV(text);
      setPreviewData(data);
      const tenantRows = buildUserTenantPreviewRows(
        data,
        tenantQuery.data?.items ?? [],
      );
      setTenantPreviewRows(tenantRows);
      setSelectedTenantMatches(
        Object.fromEntries(
          tenantRows.map((row) => [
            row.row.rowNumber,
            row.defaultTenantId || "__create__",
          ]),
        ),
      );
      setSelectedTenantCreateSlugs(
        Object.fromEntries(
          tenantRows.map((row) => [row.row.rowNumber, row.defaultCreateSlug]),
        ),
      );
      setParsing(false);
    };
    reader.readAsText(file);
  };

  const handleUpload = async () => {
    if (previewData.length > 0) {
      setPreparing(true);
      try {
        const users = await resolveUserImportTenants();
        mutation.mutate(users);
      } finally {
        setPreparing(false);
      }
    }
  };

  const resolveUserImportTenants = async () => {
    const tenants = tenantQuery.data?.items ?? [];
    const tenantByKey = new Map<
      string,
      { id: string; slug: string; emailDomain: string }
    >();

    for (const preview of tenantPreviewRows) {
      const key = tenantImportKeyFromRow(preview.row);
      const selected =
        selectedTenantMatches[preview.row.rowNumber] ?? "__create__";
      if (selected !== "__create__") {
        const tenant = tenants.find((item) => item.id === selected);
        if (tenant) {
          tenantByKey.set(key, {
            id: tenant.id,
            slug: tenant.slug,
            emailDomain: preview.row.emailDomain,
          });
        }
        continue;
      }

      const created = await createTenant({
        name: preview.row.name || preview.row.slug,
        slug:
          selectedTenantCreateSlugs[preview.row.rowNumber] ||
          preview.defaultCreateSlug,
        type: preview.row.type || "COMPANY",
        parentId: preview.row.parentTenantId || undefined,
        description: preview.row.memo,
        domains: splitTenantImportDomains(preview.row.emailDomain),
        status: "active",
      });
      tenantByKey.set(key, {
        id: created.id,
        slug: created.slug,
        emailDomain: preview.row.emailDomain,
      });
    }

    return previewData.map((user, index) => {
      const key = tenantImportKeyFromUser(user);
      const resolvedTenant = key ? tenantByKey.get(key) : undefined;
      const emailPreview = hanmacEmailPreviews[index];
      const { tenantImport: _tenantImport, ...payload } = user;
      return {
        ...payload,
        email: emailPreview?.finalEmail ?? payload.email,
        tenantId: resolvedTenant?.id ?? payload.tenantId,
        tenantSlug: resolvedTenant?.slug ?? payload.tenantSlug,
        emailDomain: resolvedTenant?.emailDomain ?? payload.emailDomain,
      };
    });
  };

  const downloadTemplate = () => {
    const headers =
      "email,name,phone,role,tenant_slug,department,grade,position,jobTitle,employee_id,tenant_slug1,department1,grade1,position1,jobTitle1,employee_id1";
    const example =
      "user1@example.com,홍길동,010-1234-5678,user,tenant-slug,개발팀,수석,팀장,프론트엔드,EMP001,second-tenant,센터,책임,,Architecture,EMP002";
    const blob = new Blob([`${headers}\n${example}`], {
      type: "text/csv;charset=utf-8;",
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "user_bulk_template.csv";
    a.click();
    URL.revokeObjectURL(url);
  };

  const reset = () => {
    setFile(null);
    setPreviewData([]);
    setTenantPreviewRows([]);
    setSelectedTenantMatches({});
    setSelectedTenantCreateSlugs({});
    setResults(null);
    if (fileInputRef.current) fileInputRef.current.value = "";
  };

  const successCount = results?.filter((r) => r.success).length ?? 0;
  const failCount = results ? results.length - successCount : 0;
  const tenants = tenantQuery.data?.items ?? [];
  const existingHanmacLocalParts = React.useMemo(() => {
    const values = new Set<string>();
    for (const user of usersQuery.data?.items ?? []) {
      if (!isHanmacFamilyUser(user, tenants)) {
        continue;
      }
      const localPart = emailLocalPart(user.email);
      if (localPart) values.add(localPart);
    }
    return values;
  }, [tenants, usersQuery.data?.items]);
  const hanmacEmailPreviews = React.useMemo(() => {
    const batchLocalParts = new Set<string>();
    return previewData.map((user) => {
      const tenant = tenants.find(
        (item) =>
          item.slug.toLowerCase() === user.tenantSlug?.trim().toLowerCase(),
      );
      if (!isHanmacFamilyTenant(tenant, tenants)) {
        return undefined;
      }
      return buildHanmacImportEmailPreview(
        user,
        existingHanmacLocalParts,
        batchLocalParts,
      );
    });
  }, [existingHanmacLocalParts, previewData, tenants]);
  const hasBlockingHanmacEmailRows = hanmacEmailPreviews.some(
    (preview) => preview?.status === "blockingError",
  );

  return (
    <Dialog
      open={open}
      onOpenChange={(val) => {
        setOpen(val);
        if (!val) reset();
      }}
    >
      <DialogTrigger asChild>
        <Button
          variant="outline"
          className="gap-2"
          data-testid="bulk-import-btn"
        >
          <Upload size={16} />
          {t("ui.admin.users.list.bulk_import", "일괄 등록 (CSV)")}
        </Button>
      </DialogTrigger>
      <DialogContent className="max-w-2xl">
        <DialogHeader>
          <DialogTitle data-testid="bulk-upload-title">
            {t("ui.admin.users.bulk.title", "사용자 일괄 등록")}
          </DialogTitle>
          <DialogDescription>
            {t(
              "msg.admin.users.bulk.description",
              "CSV 파일을 업로드하여 여러 사용자를 한 번에 등록합니다.",
            )}
          </DialogDescription>
        </DialogHeader>

        {!results ? (
          <div className="space-y-4 py-4">
            <div className="flex justify-between items-center">
              <Button
                variant="ghost"
                size="sm"
                onClick={downloadTemplate}
                className="gap-2"
              >
                <Download size={14} />
                {t("ui.admin.users.bulk.download_template", "템플릿 다운로드")}
              </Button>
              <input
                type="file"
                accept=".csv"
                className="hidden"
                ref={fileInputRef}
                onChange={handleFileChange}
              />
              <Button
                onClick={() => fileInputRef.current?.click()}
                variant="secondary"
              >
                {file
                  ? t("ui.common.change_file", "파일 변경")
                  : t("ui.common.select_file", "파일 선택")}
              </Button>
            </div>

            {file && (
              <div className="rounded-lg border p-4 bg-muted/20">
                <div className="flex items-center gap-3 mb-2">
                  <FileText className="text-primary" />
                  <span className="font-medium">{file.name}</span>
                  <span className="text-xs text-muted-foreground">
                    ({(file.size / 1024).toFixed(1)} KB)
                  </span>
                </div>
                {parsing ? (
                  <div className="flex items-center gap-2 text-sm text-muted-foreground">
                    <Loader2 size={14} className="animate-spin" />
                    {t("msg.common.parsing", "파싱 중...")}
                  </div>
                ) : (
                  <div className="text-sm text-muted-foreground">
                    {t(
                      "msg.admin.users.bulk.parsed_count",
                      "{{count}}명의 사용자가 감지되었습니다.",
                      { count: previewData.length },
                    )}
                  </div>
                )}
              </div>
            )}

            {tenantPreviewRows.length > 0 && (
              <div
                className="rounded-md border p-3 text-sm"
                data-testid="user-import-tenant-resolution"
              >
                <div className="mb-2 font-medium">
                  {t("ui.admin.users.bulk.tenant_resolution", "테넌트 매핑")}
                </div>
                <div className="space-y-2">
                  {tenantPreviewRows.map((preview) => (
                    <div
                      key={preview.row.rowNumber}
                      className="grid gap-2 sm:grid-cols-[1fr_1fr]"
                    >
                      <div>
                        <div className="font-medium">{preview.row.name}</div>
                        <div className="font-mono text-xs text-muted-foreground">
                          {preview.row.slug}
                        </div>
                      </div>
                      <div className="space-y-2">
                        <select
                          className="h-9 w-full rounded-md border border-input bg-background px-3 text-sm"
                          value={
                            selectedTenantMatches[preview.row.rowNumber] ??
                            "__create__"
                          }
                          onChange={(event) =>
                            setSelectedTenantMatches((prev) => ({
                              ...prev,
                              [preview.row.rowNumber]: event.target.value,
                            }))
                          }
                        >
                          <option value="__create__">
                            {t(
                              "ui.admin.users.bulk.create_missing_tenant",
                              "신규 생성",
                            )}
                          </option>
                          {preview.candidates.map((candidate) => (
                            <option
                              key={candidate.tenantId}
                              value={candidate.tenantId}
                            >
                              {candidate.name} ({candidate.slug})
                            </option>
                          ))}
                        </select>
                        {(selectedTenantMatches[preview.row.rowNumber] ??
                          "__create__") === "__create__" && (
                          <input
                            className="h-9 w-full rounded-md border border-input bg-background px-3 font-mono text-sm"
                            value={
                              selectedTenantCreateSlugs[
                                preview.row.rowNumber
                              ] ?? ""
                            }
                            onChange={(event) =>
                              setSelectedTenantCreateSlugs((prev) => ({
                                ...prev,
                                [preview.row.rowNumber]: event.target.value,
                              }))
                            }
                          />
                        )}
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            )}

            {previewData.length > 0 && (
              <ScrollArea className="h-[200px] rounded-md border">
                <table className="w-full text-sm">
                  <thead className="bg-muted sticky top-0">
                    <tr>
                      <th className="p-2 text-left">Email</th>
                      <th className="p-2 text-left">Name</th>
                      <th className="p-2 text-left">Tenant</th>
                      <th className="p-2 text-left">Status</th>
                    </tr>
                  </thead>
                  <tbody>
                    {previewData.slice(0, 10).map((u, index) => (
                      <tr key={`${u.email}-${index}`} className="border-t">
                        <td className="p-2">
                          <input
                            className="h-8 w-full min-w-[180px] rounded-md border border-input bg-background px-2 font-mono text-xs"
                            value={
                              hanmacEmailPreviews[index]?.finalEmail ?? u.email
                            }
                            onChange={(event) =>
                              setPreviewData((prev) =>
                                prev.map((item, itemIndex) =>
                                  itemIndex === index
                                    ? { ...item, email: event.target.value }
                                    : item,
                                ),
                              )
                            }
                          />
                        </td>
                        <td className="p-2">{u.name}</td>
                        <td className="p-2">{u.tenantSlug || "-"}</td>
                        <td
                          className={`p-2 text-xs ${hanmacEmailStatusClass(
                            hanmacEmailPreviews[index],
                          )}`}
                        >
                          {hanmacEmailStatusLabel(hanmacEmailPreviews[index])}
                          {hanmacEmailPreviews[index]?.reason && (
                            <div>{hanmacEmailPreviews[index]?.reason}</div>
                          )}
                        </td>
                      </tr>
                    ))}
                    {previewData.length > 10 && (
                      <tr>
                        <td
                          colSpan={4}
                          className="p-2 text-center text-muted-foreground italic"
                        >
                          ... and {previewData.length - 10} more users
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </ScrollArea>
            )}
          </div>
        ) : (
          <div className="space-y-4 py-4">
            <div className="flex items-center gap-4 p-4 rounded-lg bg-muted/30 border">
              <div className="flex-1 text-center">
                <div className="text-2xl font-bold text-green-600">
                  {successCount}
                </div>
                <div className="text-xs text-muted-foreground uppercase">
                  {t("ui.common.success", "성공")}
                </div>
              </div>
              <div className="w-px h-10 bg-border" />
              <div className="flex-1 text-center">
                <div className="text-2xl font-bold text-destructive">
                  {failCount}
                </div>
                <div className="text-xs text-muted-foreground uppercase">
                  {t("ui.common.fail", "실패")}
                </div>
              </div>
            </div>

            <ScrollArea className="h-[250px] rounded-md border">
              <div className="p-2 space-y-2">
                {results.map((r) => (
                  <div
                    key={r.email}
                    className="flex items-start gap-3 p-2 rounded border bg-card text-sm"
                  >
                    {r.success ? (
                      <CheckCircle2
                        size={16}
                        className="text-green-500 mt-0.5"
                      />
                    ) : (
                      <AlertCircle
                        size={16}
                        className="text-destructive mt-0.5"
                      />
                    )}
                    <div className="flex-1 min-w-0">
                      <div className="font-medium truncate">{r.email}</div>
                      {!r.success && (
                        <div className="text-xs text-destructive">
                          {r.message}
                        </div>
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </ScrollArea>
          </div>
        )}

        <DialogFooter>
          {!results ? (
            <Button
              onClick={handleUpload}
              disabled={
                previewData.length === 0 ||
                mutation.isPending ||
                preparing ||
                hasBlockingHanmacEmailRows
              }
              className="w-full sm:w-auto"
              data-testid="bulk-start-btn"
            >
              {(mutation.isPending || preparing) && (
                <Loader2 size={16} className="mr-2 animate-spin" />
              )}
              {t("ui.admin.users.bulk.start_upload", "등록 시작")}
            </Button>
          ) : (
            <Button
              onClick={() => setOpen(false)}
              className="w-full sm:w-auto"
              data-testid="bulk-close-dialog-btn"
            >
              {t("ui.common.close", "닫기")}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
