"use client";

import Link from "next/link";
import { useEffect, useRef, useState } from "react";

import { api } from "@/lib/api/client";
import type { components } from "@/lib/api/schema";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";

type Report = { counts: Record<string, number>; unmapped_tags: string[] };
type Preview = components["schemas"]["ImportPreview"];
type Dup = components["schemas"]["DuplicateMatch"];
type Tree = components["schemas"]["TreeRead"];
type Action = "new" | "skip" | "merge" | "overwrite";

const ACTIONS: { value: Action; label: string }[] = [
  { value: "new", label: "Import as new" },
  { value: "merge", label: "Merge into existing" },
  { value: "skip", label: "Skip (use existing)" },
  { value: "overwrite", label: "Overwrite existing" },
];

const fieldCls = "h-9 rounded-md border border-[var(--border)] bg-[var(--surface)] px-2 text-sm";

/**
 * GEDCOM import with a selectable destination (a new tree, or an existing one).
 * Importing into an existing tree previews likely duplicates so each can be
 * resolved (new / skip / merge / overwrite) before anything is written.
 *
 * @param fixedTreeId  When set, the destination defaults to that tree (the
 *   tree-scoped Import page). When omitted (the global Import page), the user
 *   picks a destination.
 */
export function GedcomImport({ fixedTreeId }: { fixedTreeId?: string }) {
  const [trees, setTrees] = useState<Tree[]>([]);
  const [mode, setMode] = useState<"new" | "existing">(fixedTreeId ? "existing" : "new");
  const [chosenTreeId, setChosenTreeId] = useState(fixedTreeId ?? "");
  const [newName, setNewName] = useState("");

  const [busy, setBusy] = useState(false);
  const [report, setReport] = useState<Report | null>(null);
  const [importedTreeId, setImportedTreeId] = useState<string | null>(null);
  const [file, setFile] = useState<File | null>(null);
  const [preview, setPreview] = useState<Preview | null>(null);
  const [resolutions, setResolutions] = useState<Record<string, Action>>({});
  const fileRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    api.GET("/api/v1/trees").then((r) => setTrees(r.data ?? []));
  }, []);

  function resetRun() {
    setReport(null);
    setImportedTreeId(null);
    setPreview(null);
    setFile(null);
    setResolutions({});
  }

  async function postImport(tid: string, f: File, resolutionsJson?: string) {
    const fd = new FormData();
    fd.append("file", f);
    if (resolutionsJson) fd.append("resolutions", resolutionsJson);
    const resp = await fetch(`/api/v1/trees/${tid}/gedcom/import`, {
      method: "POST",
      body: fd,
      credentials: "include",
    });
    if (resp.ok) {
      setReport(await resp.json());
      setImportedTreeId(tid);
    }
  }

  async function onFile(e: React.ChangeEvent<HTMLInputElement>) {
    const f = e.target.files?.[0];
    if (fileRef.current) fileRef.current.value = "";
    if (!f) return;
    setBusy(true);
    resetRun();

    if (mode === "new") {
      const { data } = await api.POST("/api/v1/trees", {
        body: { name: newName.trim() || "Imported tree" },
      });
      if (data) await postImport(data.id, f);
      setBusy(false);
      return;
    }

    if (!chosenTreeId) {
      setBusy(false);
      return;
    }

    // Existing tree — preview duplicates first.
    setFile(f);
    const fd = new FormData();
    fd.append("file", f);
    const resp = await fetch(`/api/v1/trees/${chosenTreeId}/gedcom/preview`, {
      method: "POST",
      body: fd,
      credentials: "include",
    });
    if (resp.ok) {
      const pv: Preview = await resp.json();
      setPreview(pv);
      const init: Record<string, Action> = {};
      for (const d of pv.potential_duplicates) init[d.xref] = d.score === "high" ? "merge" : "new";
      setResolutions(init);
    }
    setBusy(false);
  }

  async function runImport() {
    if (!file || !chosenTreeId) return;
    setBusy(true);
    const map: Record<string, { action: Action; target_id: string }> = {};
    for (const d of preview?.potential_duplicates ?? []) {
      const action = resolutions[d.xref] ?? "new";
      if (action !== "new") map[d.xref] = { action, target_id: d.existing_person_id };
    }
    await postImport(chosenTreeId, file, JSON.stringify(map));
    setPreview(null);
    setFile(null);
    setBusy(false);
  }

  const dups = preview?.potential_duplicates ?? [];

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">Import a GEDCOM file</CardTitle>
      </CardHeader>
      <CardContent className="space-y-4">
        {!preview && (
          <>
            <label className="flex items-center gap-2 text-sm">
              <input
                type="radio"
                checked={mode === "new"}
                onChange={() => {
                  setMode("new");
                  resetRun();
                }}
              />
              Import into a <strong>new tree</strong>
            </label>
            {mode === "new" && (
              <Input
                className="max-w-xs"
                placeholder="New tree name"
                value={newName}
                onChange={(e) => setNewName(e.target.value)}
              />
            )}

            <label className="flex items-center gap-2 text-sm">
              <input
                type="radio"
                checked={mode === "existing"}
                onChange={() => {
                  setMode("existing");
                  resetRun();
                }}
              />
              Import into an <strong>existing tree</strong> (checks for duplicates)
            </label>
            {mode === "existing" && (
              <select
                className={`${fieldCls} max-w-xs`}
                value={chosenTreeId}
                onChange={(e) => setChosenTreeId(e.target.value)}
              >
                <option value="">— choose a tree —</option>
                {trees.map((t) => (
                  <option key={t.id} value={t.id}>
                    {t.name}
                  </option>
                ))}
              </select>
            )}

            <input
              ref={fileRef}
              type="file"
              accept=".ged,.gedcom,text/plain"
              onChange={onFile}
              className="hidden"
            />
            <Button
              onClick={() => fileRef.current?.click()}
              disabled={busy || (mode === "existing" && !chosenTreeId)}
            >
              {busy ? "Working…" : "Choose GEDCOM file"}
            </Button>
          </>
        )}

        {/* Duplicate-resolution step */}
        {preview && (
          <div className="space-y-4">
            <div className="flex flex-wrap gap-x-6 gap-y-1 text-sm text-[var(--muted)]">
              {Object.entries(preview.counts).map(([k, v]) => (
                <span key={k}>
                  <span className="font-medium text-[var(--foreground)]">{v}</span> {k}
                </span>
              ))}
            </div>

            {dups.length === 0 ? (
              <p className="rounded-md bg-bronze/[0.08] px-3 py-2 text-sm">
                No likely duplicates found — everyone will be imported as new.
              </p>
            ) : (
              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <h3 className="text-sm font-semibold">
                    {dups.length} possible duplicate{dups.length === 1 ? "" : "s"}
                  </h3>
                  <label className="flex items-center gap-2 text-xs text-[var(--muted)]">
                    Set all to
                    <select
                      className={fieldCls}
                      defaultValue=""
                      onChange={(e) => {
                        const a = e.target.value as Action;
                        const all: Record<string, Action> = {};
                        for (const d of dups) all[d.xref] = a;
                        setResolutions(all);
                      }}
                    >
                      <option value="" disabled>
                        choose…
                      </option>
                      {ACTIONS.map((a) => (
                        <option key={a.value} value={a.value}>
                          {a.label}
                        </option>
                      ))}
                    </select>
                  </label>
                </div>
                <ul className="divide-y divide-[var(--border)] rounded-lg border border-[var(--border)]">
                  {dups.map((d: Dup) => (
                    <li
                      key={d.xref}
                      className="flex flex-wrap items-center justify-between gap-3 px-3 py-2 text-sm"
                    >
                      <div className="min-w-0">
                        <span className="font-medium">{d.incoming_name}</span>
                        {d.incoming_birth_year && (
                          <span className="text-[var(--muted)]"> b. {d.incoming_birth_year}</span>
                        )}
                        <span className="text-[var(--muted)]"> ↔ </span>
                        <span>{d.existing_name}</span>
                        {d.existing_birth_year && (
                          <span className="text-[var(--muted)]"> b. {d.existing_birth_year}</span>
                        )}
                        <span
                          className={`ml-2 rounded px-1.5 py-0.5 text-xs ${
                            d.score === "high"
                              ? "bg-bronze/15 text-bronze"
                              : "bg-[var(--border)]/50 text-[var(--muted)]"
                          }`}
                        >
                          {d.score}
                        </span>
                      </div>
                      <select
                        className={fieldCls}
                        value={resolutions[d.xref] ?? "new"}
                        onChange={(e) =>
                          setResolutions((r) => ({ ...r, [d.xref]: e.target.value as Action }))
                        }
                      >
                        {ACTIONS.map((a) => (
                          <option key={a.value} value={a.value}>
                            {a.label}
                          </option>
                        ))}
                      </select>
                    </li>
                  ))}
                </ul>
              </div>
            )}

            <div className="flex gap-2">
              <Button onClick={runImport} disabled={busy}>
                {busy ? "Importing…" : "Run import"}
              </Button>
              <Button variant="ghost" onClick={resetRun} disabled={busy}>
                Cancel
              </Button>
            </div>
          </div>
        )}

        {report && (
          <div className="space-y-3 rounded-lg border border-[var(--border)] p-4">
            <div className="font-medium">Import complete</div>
            <div className="flex flex-wrap gap-x-6 gap-y-1 text-sm text-[var(--muted)]">
              {Object.entries(report.counts).map(([k, v]) => (
                <span key={k}>
                  <span className="font-medium text-[var(--foreground)]">{v}</span> {k}
                </span>
              ))}
            </div>
            {report.unmapped_tags.length > 0 && (
              <div className="text-xs text-[var(--muted)]">
                Unmapped tags (skipped): {report.unmapped_tags.join(", ")}
              </div>
            )}
            {importedTreeId && (
              <Link
                href={`/trees/${importedTreeId}`}
                className="inline-block text-sm text-bronze hover:underline"
              >
                Open the tree →
              </Link>
            )}
          </div>
        )}
      </CardContent>
    </Card>
  );
}
