import { useRef, useState } from "react";
import type { HostData } from "@/types/index";
import { useTranslation } from "react-i18next";
import { Server, RefreshCw, CheckSquare, Square, Download } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/button";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/dialog";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/select";
import {
  discoverProxmoxGuestsStream,
  bulkImportSSHHosts,
  getSSHHosts,
} from "@/main-axios";
import type { SSHHostWithStatus } from "@/main-axios";
import type { ProxmoxGuest } from "@/types/proxmox";
import { resolveProxmoxImportAuth } from "./proxmox-import-auth";

interface ProxmoxDiscoverDialogProps {
  open: boolean;
  onClose: () => void;
  hosts: SSHHostWithStatus[];
  onHostsChanged: (hosts: SSHHostWithStatus[]) => void;
  /** Pre-select a specific host and skip the host picker */
  preselectedHostId?: number;
  /** Credential to use for imported hosts */
  defaultCredentialId?: number | null;
  /** Auth type to use for imported hosts */
  defaultAuthType?: string;
  /** Username from the default credential */
  defaultUsername?: string;
}

export function ProxmoxDiscoverDialog({
  open,
  onClose,
  hosts,
  onHostsChanged,
  preselectedHostId,
  defaultCredentialId,
  defaultAuthType,
  defaultUsername,
}: ProxmoxDiscoverDialogProps) {
  const { t } = useTranslation();
  const [selectedHostId, setSelectedHostId] = useState<string>(
    preselectedHostId ? String(preselectedHostId) : "",
  );
  const [discovering, setDiscovering] = useState(false);
  const [progress, setProgress] = useState<{
    done: number;
    total: number;
  } | null>(null);
  const streamCloseRef = useRef<(() => void) | null>(null);
  const [guests, setGuests] = useState<ProxmoxGuest[] | null>(null);
  const [discoveredCredentialId, setDiscoveredCredentialId] = useState<
    number | null
  >(null);
  const [discoveredJumpHosts, setDiscoveredJumpHosts] = useState<
    unknown[] | null
  >(null);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [importing, setImporting] = useState(false);

  // When opened from the dropdown (no preselectedHostId), only show Proxmox-enabled hosts
  const sshHosts = hosts.filter(
    (h) => !("isFolder" in h) && h.enableProxmox === true,
  );

  // The Proxmox host the discovery runs against — imported guests are grouped
  // into a folder named after it. Use the same id resolution as discovery so
  // it also works when launched directly from a host action (preselectedHostId).
  const effectiveHostId =
    preselectedHostId != null ? String(preselectedHostId) : selectedHostId;
  const sourceHost = hosts.find(
    (h) => !("isFolder" in h) && String(h.id) === effectiveHostId,
  );
  const importFolder = sourceHost?.name || "Proxmox";

  function reset() {
    if (!preselectedHostId) setSelectedHostId("");
    setGuests(null);
    setDiscoveredCredentialId(null);
    setDiscoveredJumpHosts(null);
    setSelected(new Set());
    streamCloseRef.current?.();
    streamCloseRef.current = null;
    setProgress(null);
    setDiscovering(false);
    setImporting(false);
  }

  function handleDiscover() {
    const hostId =
      preselectedHostId ?? (selectedHostId ? Number(selectedHostId) : null);
    if (!hostId) return;
    setDiscovering(true);
    setGuests(null);
    setDiscoveredCredentialId(null);
    setDiscoveredJumpHosts(null);
    setSelected(new Set());
    setProgress(null);
    streamCloseRef.current?.();
    streamCloseRef.current = discoverProxmoxGuestsStream(hostId, {
      onProgress: (done, total) => setProgress({ done, total }),
      onResult: (result) => {
        setGuests(result.guests);
        setDiscoveredCredentialId(result.credentialId ?? null);
        setDiscoveredJumpHosts(result.jumpHosts ?? null);
        setSelected(
          new Set(
            result.guests
              .filter((g) => g.status === "running")
              .map((g) => g.vmid),
          ),
        );
        setDiscovering(false);
        setProgress(null);
        streamCloseRef.current = null;
      },
      onError: (message) => {
        toast.error(message ?? t("hosts.proxmoxDiscoveryFailed"));
        setDiscovering(false);
        setProgress(null);
        streamCloseRef.current = null;
      },
    });
  }

  async function handleImport() {
    if (!guests || selected.size === 0) return;
    setImporting(true);
    try {
      // Prefer explicitly configured credential, then fall back to the host's own credential
      const credId = defaultCredentialId ?? discoveredCredentialId;
      const importAuth = resolveProxmoxImportAuth(defaultAuthType, credId);

      const selectedGuests = guests.filter((g) => selected.has(g.vmid));

      const toImport = selectedGuests.map((g) => ({
        name: g.name,
        // No IP discovered (e.g. QEMU without a running guest agent): import
        // with a placeholder so the host is created and the user can fill in
        // the real IP. Re-sync keeps the manual value (guest.ip || existing.ip).
        ip: g.ip || "0.0.0.0",
        port: g.connectionType === "rdp" ? 3389 : 22,
        username:
          importAuth.authType === "credential"
            ? ""
            : (defaultUsername ?? "root"),
        folder: importFolder,
        // Inherit the jump-host chain from the scanned Proxmox host so the
        // imported guests are reachable the same way; user can override.
        jumpHosts: discoveredJumpHosts ?? undefined,
        ...importAuth,
        enableTerminal: g.connectionType !== "rdp",
        enableFileManager: g.connectionType !== "rdp",
        enableTunnel: g.connectionType !== "rdp",
        enableSsh: g.connectionType !== "rdp",
        enableRdp: g.connectionType === "rdp",
        enableDocker: g.enableDocker,
        connectionType: g.connectionType,
        tags: [
          "proxmox",
          g.type,
          g.node,
          g.type === "lxc" ? `ct-${g.vmid}` : `vm-${g.vmid}`,
          ...(g.enableDocker ? ["docker"] : []),
        ],
        proxmoxConfig: {
          source: {
            source: "proxmox",
            sourceHostId: Number(effectiveHostId),
            node: g.node,
            vmid: g.vmid,
            type: g.type,
            lastSeenAt: new Date().toISOString(),
            lastStatus: g.status,
            missingSince: null,
          },
        },
      }));

      const result = toImport.length
        ? await bulkImportSSHHosts(toImport as unknown as HostData[], false)
        : { success: 0, updated: 0, skipped: 0, failed: 0 };

      if (toImport.length) {
        const updated = await getSSHHosts();
        onHostsChanged(updated);
        window.dispatchEvent(new CustomEvent("termix:hosts-changed"));
      }

      const msg = [
        result.success
          ? t("hosts.proxmoxResultImported", { count: result.success })
          : null,
        result.updated
          ? t("hosts.proxmoxResultUpdated", { count: result.updated })
          : null,
        result.failed
          ? t("hosts.proxmoxResultFailed", { count: result.failed })
          : null,
      ]
        .filter(Boolean)
        .join(", ");
      toast.success(t("hosts.proxmoxImportComplete", { summary: msg }));

      if (result.failed === 0) {
        reset();
        onClose();
      }
    } catch (err: any) {
      toast.error(err?.message ?? t("hosts.proxmoxImportFailed"));
    } finally {
      setImporting(false);
    }
  }

  const nodeGroups = guests
    ? guests.reduce(
        (acc, g) => {
          if (!acc[g.node]) acc[g.node] = [];
          acc[g.node].push(g);
          return acc;
        },
        {} as Record<string, ProxmoxGuest[]>,
      )
    : {};

  const canDiscover = preselectedHostId != null || !!selectedHostId;

  return (
    <Dialog
      open={open}
      onOpenChange={(v) => {
        if (!v) {
          reset();
          onClose();
        }
      }}
    >
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <Server className="size-4" />
            {t("hosts.proxmoxImportTitle")}
          </DialogTitle>
          <a
            href="https://docs.termix.site/features/files-and-hosts/proxmox-import"
            target="_blank"
            rel="noreferrer"
            className="text-[10px] text-accent-brand hover:underline"
          >
            {t("hosts.docsLink")}
          </a>
        </DialogHeader>

        <div className="space-y-3">
          {/* Host selector — hidden when launched from a specific host */}
          {!preselectedHostId && (
            <div className="flex gap-2">
              <Select
                value={selectedHostId}
                onValueChange={setSelectedHostId}
                disabled={discovering}
              >
                <SelectTrigger className="flex-1 text-xs h-8">
                  <SelectValue placeholder={t("hosts.proxmoxSelectHost")} />
                </SelectTrigger>
                <SelectContent>
                  {sshHosts.map((h) => (
                    <SelectItem
                      key={h.id}
                      value={String(h.id)}
                      className="text-xs"
                    >
                      {h.name || h.ip}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              <Button
                size="sm"
                variant="outline"
                disabled={!canDiscover || discovering}
                onClick={handleDiscover}
                className="shrink-0"
              >
                <RefreshCw
                  className={`size-3.5 mr-1.5 ${discovering ? "animate-spin" : ""}`}
                />
                {t("hosts.proxmoxDiscover")}
              </Button>
            </div>
          )}

          {/* When launched from a specific host, show Discover directly */}
          {preselectedHostId && !guests && (
            <Button
              size="sm"
              variant="outline"
              disabled={discovering}
              onClick={handleDiscover}
              className="w-full"
            >
              <RefreshCw
                className={`size-3.5 mr-1.5 ${discovering ? "animate-spin" : ""}`}
              />
              {discovering
                ? progress
                  ? `${t("hosts.proxmoxDiscovering")} ${progress.done}/${progress.total}`
                  : t("hosts.proxmoxDiscovering")
                : t("hosts.proxmoxDiscoverGuests")}
            </Button>
          )}

          {/* Guest list */}
          {guests !== null && (
            <div className="space-y-1.5">
              <div className="flex items-center justify-between text-xs text-muted-foreground">
                <span>
                  {t("hosts.proxmoxGuestsSelected", {
                    count: guests.length,
                    selected: selected.size,
                  })}
                </span>
                <div className="flex gap-2">
                  <button
                    className="hover:text-foreground transition-colors"
                    onClick={() =>
                      setSelected(new Set(guests.map((g) => g.vmid)))
                    }
                  >
                    {t("hosts.proxmoxSelectAll")}
                  </button>
                  <span>·</span>
                  <button
                    className="hover:text-foreground transition-colors"
                    onClick={() => setSelected(new Set())}
                  >
                    {t("hosts.proxmoxDeselectAll")}
                  </button>
                </div>
              </div>

              {guests.length === 0 ? (
                <p className="text-xs text-muted-foreground py-4 text-center">
                  {t("hosts.proxmoxNoGuests")}
                </p>
              ) : (
                <div className="max-h-64 overflow-y-auto rounded-md border border-border divide-y divide-border">
                  {Object.entries(nodeGroups).map(([node, nodeGuests]) => (
                    <div key={node}>
                      <div className="px-2 py-1 text-[10px] font-medium text-muted-foreground bg-muted/50 uppercase tracking-wider">
                        {node}
                      </div>
                      {nodeGuests.map((g) => (
                        <button
                          key={g.vmid}
                          className="w-full flex items-center gap-2 px-2 py-1.5 text-xs hover:bg-accent transition-colors text-left"
                          onClick={() => {
                            setSelected((prev) => {
                              const next = new Set(prev);
                              if (next.has(g.vmid)) next.delete(g.vmid);
                              else next.add(g.vmid);
                              return next;
                            });
                          }}
                        >
                          {selected.has(g.vmid) ? (
                            <CheckSquare className="size-3.5 text-primary shrink-0" />
                          ) : (
                            <Square className="size-3.5 text-muted-foreground shrink-0" />
                          )}
                          <span className="flex-1 truncate">{g.name}</span>
                          <span className="text-muted-foreground text-[10px] shrink-0">
                            {g.type.toUpperCase()} {g.vmid}
                          </span>
                          <span
                            className={`shrink-0 text-[10px] ${g.status === "running" ? "text-green-400" : "text-muted-foreground"}`}
                          >
                            {g.status}
                          </span>
                          <span
                            className={`shrink-0 text-[10px] font-mono ${
                              g.ip
                                ? "text-muted-foreground"
                                : "text-amber-400/80 italic"
                            }`}
                          >
                            {g.ip || "no IP"}
                          </span>
                        </button>
                      ))}
                    </div>
                  ))}
                </div>
              )}
            </div>
          )}
        </div>

        <DialogFooter>
          <Button
            variant="ghost"
            size="sm"
            onClick={() => {
              reset();
              onClose();
            }}
          >
            {t("common.cancel")}
          </Button>
          {guests !== null && selected.size > 0 && (
            <Button size="sm" disabled={importing} onClick={handleImport}>
              {importing ? (
                <RefreshCw className="size-3.5 animate-spin mr-1.5" />
              ) : (
                <Download className="size-3.5 mr-1.5" />
              )}
              {t("hosts.proxmoxImportButton", { count: selected.size })}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
