import { type JSX, useState, useCallback, useEffect } from "react";
import { z } from "zod";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
import { Button } from "../ui/button";

import { Loader2, Download, AlertCircle } from "lucide-react";

function ClaudeCodeIcon(): JSX.Element {
  return (
    <svg
      fill="currentColor"
      fillRule="evenodd"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
      className="size-6 shrink-0"
    >
      <title>Claude Code</title>
      <path
        clipRule="evenodd"
        d="M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z"
      />
    </svg>
  );
}

function OpenCodeIcon(): JSX.Element {
  return (
    <svg
      fill="currentColor"
      fillRule="evenodd"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
      className="size-6 shrink-0"
    >
      <title>OpenCode</title>
      <path d="M16 6H8v12h8V6zm4 16H4V2h16v20z" />
    </svg>
  );
}

function MiMoCodeIcon(): JSX.Element {
  return (
    <svg
      fill="currentColor"
      viewBox="0 0 24 24"
      xmlns="http://www.w3.org/2000/svg"
      className="size-6 shrink-0"
    >
      <title>MiMo Code</title>
      <text
        x="12"
        y="18"
        textAnchor="middle"
        fontSize="16"
        fontWeight="800"
        fontFamily="system-ui, sans-serif"
      >
        M
      </text>
    </svg>
  );
}

const ExternalProviderSchema = z.object({
  name: z.string(),
  apiKey: z.string(),
  format: z.enum(["anthropic", "openai"]),
  anthropicBaseUrl: z.string(),
  openaiBaseUrl: z.string(),
  models: z.array(z.string()),
  sourceTool: z.enum(["claude-code", "opencode", "mimo-code"]),
  alreadyExists: z.boolean(),
});

const ScanResponseSchema = z.object({
  providers: z.array(ExternalProviderSchema),
  warnings: z.array(z.string()).optional(),
});

const ImportResponseSchema = z.object({
  success: z.boolean().optional(),
  imported: z.number().optional(),
  message: z.string().optional(),
  errors: z.array(z.string()).optional(),
});

const sourceLogoMap: Record<string, () => JSX.Element> = {
  "claude-code": ClaudeCodeIcon,
  opencode: OpenCodeIcon,
  "mimo-code": MiMoCodeIcon,
};

type ImportWizardDialogProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onImportComplete: () => void;
};

export function ImportWizardDialog({
  open,
  onOpenChange,
  onImportComplete,
}: ImportWizardDialogProps): JSX.Element {
  const [scanning, setScanning] = useState(false);
  const [scanError, setScanError] = useState<string | null>(null);
  const [providers, setProviders] = useState<z.infer<typeof ExternalProviderSchema>[]>([]);
  const [warnings, setWarnings] = useState<string[]>([]);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [importing, setImporting] = useState(false);
  const [importResult, setImportResult] = useState<string | null>(null);
  const [importError, setImportError] = useState<string | null>(null);

  const scan = useCallback(() => {
    setScanning(true);
    setScanError(null);
    setWarnings([]);
    setProviders([]);
    setSelected(new Set());
    setImportResult(null);
    setImportError(null);

    fetch("/api/providers/scan")
      .then((res) => {
        if (!res.ok) {
          return res.text().then((text) => {
            setScanError(`Scan failed (${res.status}): ${text}`);
          });
        }
        return res.json().then((data: unknown) => {
          const parsed = ScanResponseSchema.safeParse(data);
          if (!parsed.success) {
            setScanError(`Invalid response: ${parsed.error.message}`);
            return;
          }
          setProviders(parsed.data.providers);
          setWarnings(parsed.data.warnings ?? []);
          // Pre-select non-existing providers
          const indices = new Set<number>();
          parsed.data.providers.forEach((p, i) => {
            if (!p.alreadyExists) indices.add(i);
          });
          setSelected(indices);
        });
      })
      .catch((err: unknown) => {
        setScanError(err instanceof Error ? err.message : String(err));
      })
      .finally(() => {
        setScanning(false);
      });
  }, []);

  // Auto-scan when dialog opens
  useEffect(() => {
    if (open) {
      scan();
    }
  }, [open, scan]);

  const toggleProvider = useCallback((index: number) => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (next.has(index)) {
        next.delete(index);
      } else {
        next.add(index);
      }
      return next;
    });
  }, []);

  const importSelected = useCallback(() => {
    const toImport = providers.filter((_, i) => selected.has(i));
    if (toImport.length === 0) return;

    setImporting(true);
    setImportError(null);
    setImportResult(null);

    // Convert ExternalProvider[] to ProviderConfig shape for import
    const now = new Date().toISOString();
    const providersPayload = toImport.map((p) => ({
      id: window.crypto.randomUUID(),
      name: p.name,
      apiKey: p.apiKey,
      format: p.format,
      anthropicBaseUrl: p.anthropicBaseUrl,
      openaiBaseUrl: p.openaiBaseUrl,
      models: p.models,
      createdAt: now,
      updatedAt: now,
    }));

    fetch("/api/providers/import", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ providers: providersPayload }),
    })
      .then((res) => res.json())
      .then((data: unknown) => {
        const parsed = ImportResponseSchema.safeParse(data);
        if (!parsed.success) {
          setImportError(`Invalid response: ${parsed.error.message}`);
          return;
        }
        const result = parsed.data;
        // Mark imported providers as already existing so they can't be re-selected
        setProviders((prev) =>
          prev.map((p, i) => (selected.has(i) ? { ...p, alreadyExists: true } : p)),
        );
        setSelected(new Set());

        if (
          result.errors !== undefined &&
          result.errors.length > 0 &&
          result.message !== undefined
        ) {
          setImportResult(result.message);
        } else {
          setImportResult(`Imported ${result.imported ?? toImport.length} provider(s)`);
        }
        onImportComplete();
      })
      .catch((err: unknown) => {
        setImportError(err instanceof Error ? err.message : String(err));
      })
      .finally(() => {
        setImporting(false);
      });
  }, [providers, selected, onImportComplete]);

  const hasSelectable = providers.some((p) => !p.alreadyExists);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-xl max-h-[80vh] overflow-hidden flex flex-col">
        <DialogHeader>
          <DialogTitle>Import from External Tools</DialogTitle>
          <p className="text-xs text-muted-foreground">
            Detect provider configurations from Claude Code, OpenCode, and MiMo Code.
          </p>
        </DialogHeader>

        <div className="flex-1 overflow-y-auto space-y-3">
          {scanning && (
            <div className="flex items-center justify-center py-8 gap-2 text-muted-foreground">
              <Loader2 className="size-4 animate-spin" />
              <span className="text-sm">Scanning for external providers...</span>
            </div>
          )}

          {scanError !== null && (
            <div className="flex items-center gap-2 text-destructive text-sm py-4">
              <AlertCircle className="size-4" />
              {scanError}
            </div>
          )}

          {!scanning && scanError === null && providers.length === 0 && (
            <p className="text-sm text-muted-foreground py-8 text-center">
              No external provider configurations found.
              <br />
              <span className="text-xs">
                Supported tools: Claude Code (~/.claude/settings.json), OpenCode
                (~/.config/opencode/opencode.json), MiMo Code (~/.config/mimocode/mimocode.jsonc)
              </span>
            </p>
          )}

          {!scanning &&
            providers.map((p, i) => (
              <label
                key={`${p.sourceTool}-${p.name}`}
                className={`flex items-start gap-3 p-3 border rounded-md ${p.alreadyExists ? "" : "cursor-pointer hover:bg-muted/50"}`}
              >
                {!p.alreadyExists && (
                  <input
                    type="checkbox"
                    checked={selected.has(i)}
                    disabled={importing}
                    onChange={() => toggleProvider(i)}
                    className="mt-0.5 size-4"
                  />
                )}
                <div className="flex-1 min-w-0">
                  <div className="flex items-center justify-between">
                    {(() => {
                      const LogoComponent = sourceLogoMap[p.sourceTool];
                      if (LogoComponent === undefined) return null;
                      return <LogoComponent />;
                    })()}
                    {p.alreadyExists && (
                      <span className="text-[10px] text-muted-foreground">Already added</span>
                    )}
                  </div>
                  <div className="text-xs text-muted-foreground mt-1 truncate">
                    {p.models.slice(0, 4).join(", ")}
                    {p.models.length > 4 ? ` +${p.models.length - 4} more` : ""}
                  </div>
                  <div className="text-xs text-muted-foreground mt-0.5 truncate">
                    {p.format === "anthropic" ? p.anthropicBaseUrl : p.openaiBaseUrl}
                  </div>
                  <div className="text-xs text-muted-foreground mt-0.5 font-mono">
                    {p.apiKey.length > 8
                      ? `${p.apiKey.slice(0, 4)}••••${p.apiKey.slice(-4)}`
                      : "••••"}
                  </div>
                </div>
              </label>
            ))}

          {warnings.length > 0 && (
            <div className="text-xs text-muted-foreground space-y-1 border-t pt-2">
              {warnings.map((w, i) => (
                <div key={i} className="flex items-center gap-1">
                  <AlertCircle className="size-3" />
                  {w}
                </div>
              ))}
            </div>
          )}

          {importResult !== null && (
            <div className="text-sm text-green-500 border-t pt-2">{importResult}</div>
          )}

          {importError !== null && (
            <div className="text-sm text-destructive border-t pt-2">{importError}</div>
          )}
        </div>

        <div className="flex items-center justify-between pt-3 border-t">
          <Button variant="outline" size="sm" onClick={scan} disabled={scanning}>
            <Loader2 className={`size-3 mr-1 ${scanning ? "animate-spin" : ""}`} />
            Rescan
          </Button>
          <Button
            size="sm"
            onClick={importSelected}
            disabled={!hasSelectable || selected.size === 0 || importing}
          >
            <Download className="size-3 mr-1" />
            {importing ? "Importing..." : `Import Selected (${selected.size})`}
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  );
}
