import { useState } from "react";
import { AlertTriangle, ArrowRight, Check, ChevronDown, FileJson, ShieldCheck } from "lucide-react";
import Button from "./ui/Button";
import Badge from "./ui/Badge";
import { sampleJson } from "../lib/api";
import { parseJson } from "../lib/format";

function buildPayload(server, parsed) {
  const entries = Array.isArray(parsed) ? parsed : parsed.servers || [];
  const services = [];
  const errors = [];

  entries.forEach((entry, index) => {
    const domain = String(entry?.domain || "").trim();
    const ports = Array.isArray(entry?.ports) ? entry.ports : [];
    if (!domain || ports.length === 0) {
      errors.push({ index, message: "Each entry needs a domain and at least one port." });
      return;
    }
    ports.forEach((port, portIndex) => {
      const value = Number(port);
      if (!Number.isInteger(value) || value < 1 || value > 65535) {
        errors.push({ index, serviceIndex: portIndex, message: `Port "${port}" is not valid.` });
        return;
      }
      services.push({
        name: domain,
        port: value,
        endpoint: "/",
        method: "POST",
        notes: entry.is_backup ? "backup" : null,
      });
    });
  });

  return {
    payload: {
      servers: [
        {
          name: server.name,
          ipAddress: server.ipAddress,
          description: server.description,
          proxyPort: server.proxyPort ?? null,
          proxyPath: server.proxyPort ? server.proxyPath || "/api/nginx/app" : null,
          services,
        },
      ],
    },
    errors,
  };
}

function ConflictSide({ title, data, highlight = false }) {
  return (
    <div className={`rounded-lg p-2.5 ${highlight ? "border border-amber-500/30 bg-amber-500/10" : "bg-surface-3/60"}`}>
      <p className="text-[10px] font-semibold uppercase tracking-wider text-ink-muted">{title}</p>
      {data?.name && <p className="mt-0.5 truncate text-xs font-semibold text-ink">{data.name}</p>}
      {data?.description && <p className="truncate text-[11px] text-ink-muted">{data.description}</p>}
      {data?.port !== undefined && data?.port !== null && (
        <p className="mono mt-0.5 text-[10px] text-ink-muted">
          port {data.port}
          {data.method ? ` · ${data.method}` : ""}
        </p>
      )}
    </div>
  );
}

export default function ImportPanel({ server, onPreview, onApply }) {
  const [expanded, setExpanded] = useState(false);
  const [jsonInput, setJsonInput] = useState(sampleJson);
  const [preview, setPreview] = useState(null);
  const [jsonError, setJsonError] = useState("");
  const [shapeErrors, setShapeErrors] = useState([]);
  const [busy, setBusy] = useState("");

  function prepare() {
    setJsonError("");
    setShapeErrors([]);
    let parsed;
    try {
      parsed = parseJson(jsonInput);
    } catch {
      setJsonError("The JSON is not valid.");
      return null;
    }
    const result = buildPayload(server, parsed);
    setShapeErrors(result.errors);
    return result.errors.length === 0 ? result.payload : null;
  }

  async function previewImport() {
    const payload = prepare();
    if (!payload) return;
    setBusy("preview");
    try {
      setPreview(await onPreview(payload));
    } catch (err) {
      setJsonError(err.message);
    } finally {
      setBusy("");
    }
  }

  async function apply(mode) {
    const payload = prepare();
    if (!payload) return;
    setBusy(mode);
    try {
      await onApply(payload, mode);
      setPreview(null);
    } catch (err) {
      setJsonError(err.message);
      if (err.data) setPreview(err.data);
    } finally {
      setBusy("");
    }
  }

  const hasConflicts = preview?.conflicts?.length > 0;

  return (
    <div className="rounded-xl border border-line bg-surface-2/40">
      <button
        type="button"
        onClick={() => setExpanded((value) => !value)}
        className="flex w-full items-center justify-between gap-3 p-3 text-left transition hover:bg-surface-2/60"
        aria-expanded={expanded}
      >
        <span className="flex items-center gap-2.5">
          <FileJson size={15} className="text-accent" />
          <span className="text-sm font-semibold text-ink">Bulk Import</span>
          <span className="hidden text-[11px] text-ink-muted sm:inline">
            add domains &amp; ports to {server.name}
          </span>
        </span>
        <ChevronDown size={16} className={`shrink-0 text-ink-muted transition-transform ${expanded ? "rotate-180" : ""}`} />
      </button>

      {expanded && (
        <div className="grid gap-4 border-t border-line p-4">
          {!preview ? (
            <>
              <textarea
                className="input mono min-h-40 text-xs"
                spellCheck="false"
                value={jsonInput}
                onChange={(event) => setJsonInput(event.target.value)}
              />
              <p className="-mt-2 text-[11px] leading-relaxed text-ink-muted">
                One entry per service: <span className="mono text-ink-soft">{"{ domain, ports, is_backup }"}</span>.
                Each domain becomes a service on {server.name}; same domain + port already present is skipped,
                a domain with a different port is a conflict.
              </p>
              {jsonError && (
                <p className="rounded-lg border border-rose-500/30 bg-rose-500/10 px-3 py-2 text-xs font-medium text-rose-400">
                  {jsonError}
                </p>
              )}
              {shapeErrors.length > 0 && (
                <div className="rounded-lg border border-rose-500/30 bg-rose-500/10 p-3">
                  <ul className="grid gap-1.5">
                    {shapeErrors.map((errorItem, index) => (
                      <li key={index} className="mono text-[11px] text-rose-300/90">
                        #{errorItem.index}
                        {errorItem.serviceIndex !== undefined ? `.${errorItem.serviceIndex}` : ""} — {errorItem.message}
                      </li>
                    ))}
                  </ul>
                </div>
              )}
              <div className="flex justify-end">
                <Button variant="primary" icon={ArrowRight} onClick={previewImport} loading={busy === "preview"}>
                  Preview Import
                </Button>
              </div>
            </>
          ) : (
            <>
              <div className="grid grid-cols-3 gap-3">
                <div className="rounded-xl border border-line bg-surface-2/60 p-3">
                  <p className="text-[10px] font-semibold uppercase tracking-wider text-ink-muted">New services</p>
                  <p className="mt-1 text-xl font-bold text-ink">{preview.newServices?.length || 0}</p>
                </div>
                <div className="rounded-xl border border-line bg-surface-2/60 p-3">
                  <p className="text-[10px] font-semibold uppercase tracking-wider text-ink-muted">Duplicates</p>
                  <p className="mt-1 text-xl font-bold text-ink">{preview.duplicates?.length || 0}</p>
                </div>
                <div className="rounded-xl border border-line bg-surface-2/60 p-3">
                  <p className="text-[10px] font-semibold uppercase tracking-wider text-ink-muted">Conflicts</p>
                  <p className={`mt-1 text-xl font-bold ${hasConflicts ? "text-amber-400" : "text-ink"}`}>
                    {preview.conflicts?.length || 0}
                  </p>
                </div>
              </div>

              {preview.errors.length > 0 && (
                <div className="rounded-lg border border-rose-500/30 bg-rose-500/10 p-3">
                  <p className="mb-2 text-xs font-bold text-rose-400">Validation errors — fix these before applying</p>
                  <ul className="grid gap-1.5">
                    {preview.errors.map((errorItem, index) => (
                      <li key={index} className="mono text-[11px] text-rose-300/90">
                        #{errorItem.index}
                        {errorItem.serviceIndex !== undefined ? `.${errorItem.serviceIndex}` : ""} — {errorItem.message}
                      </li>
                    ))}
                  </ul>
                </div>
              )}

              {preview.duplicates.length > 0 && (
                <div className="rounded-lg border border-emerald-500/30 bg-emerald-500/10 p-3">
                  <p className="mb-2 flex items-center gap-1.5 text-xs font-bold text-emerald-400">
                    <Check size={13} /> {preview.duplicates.length} exact duplicate
                    {preview.duplicates.length === 1 ? "" : "s"} will be skipped
                  </p>
                  <div className="flex flex-wrap gap-1.5">
                    {preview.duplicates.map((dup, index) => (
                      <Badge key={index} className="mono border-emerald-500/30 bg-emerald-500/10 text-emerald-300">
                        {dup.name}:{dup.port}
                      </Badge>
                    ))}
                  </div>
                </div>
              )}

              {hasConflicts && (
                <div className="rounded-xl border border-amber-500/30 bg-amber-500/5 p-3">
                  <p className="mb-3 flex items-center gap-1.5 text-xs font-bold text-amber-400">
                    <AlertTriangle size={13} /> {preview.conflicts.length} conflict
                    {preview.conflicts.length === 1 ? "" : "s"} need confirmation
                  </p>
                  <div className="grid gap-2.5">
                    {preview.conflicts.map((conflict, index) => (
                      <div key={index} className="rounded-lg border border-line bg-surface-2/60 p-3">
                        <div className="mb-2 flex flex-wrap items-center gap-2">
                          <Badge className="border-violet-500/40 bg-violet-500/10 text-violet-300">Port conflict</Badge>
                          <span className="mono text-[11px] text-ink-soft">{conflict.key || conflict.ipAddress}</span>
                        </div>
                        <div className="grid items-center gap-2 sm:grid-cols-[1fr_auto_1fr]">
                          <ConflictSide title="Existing" data={conflict.existing} />
                          <ArrowRight size={14} className="mx-auto text-ink-muted" />
                          <ConflictSide title="Incoming" data={conflict.incoming} highlight />
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              )}

              {!hasConflicts && preview.errors.length === 0 && (
                <p className="flex items-center gap-2 rounded-lg border border-emerald-500/30 bg-emerald-500/10 px-3 py-2.5 text-xs font-medium text-emerald-400">
                  <ShieldCheck size={14} /> Import is clean — applying adds new services and skips exact duplicates.
                </p>
              )}

              <div className="flex flex-wrap justify-end gap-3 border-t border-line pt-4">
                <Button variant="ghost" onClick={() => setPreview(null)} disabled={Boolean(busy)}>
                  Back
                </Button>
                {hasConflicts ? (
                  <Button variant="amber" onClick={() => apply("overwrite")} loading={busy === "overwrite"}>
                    Confirm Overwrite
                  </Button>
                ) : (
                  <Button
                    variant="primary"
                    onClick={() => apply("skip")}
                    loading={busy === "skip"}
                    disabled={preview.errors.length > 0}
                  >
                    Apply Import
                  </Button>
                )}
              </div>
            </>
          )}
        </div>
      )}
    </div>
  );
}
