"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { Check, ChevronRight, Copy, Terminal } from "lucide-react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useWorkspaceId } from "@multica/core/hooks";
import { runtimeKeys } from "@multica/core/runtimes/queries";
import { useWSEvent } from "@multica/core/realtime";
import { api } from "@multica/core/api";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@multica/ui/components/ui/dialog";
import { Button } from "@multica/ui/components/ui/button";
import { CODE_LIGATURE_CLASS } from "@multica/ui/lib/code-style";
import { copyText } from "@multica/ui/lib/clipboard";
import { cn } from "@multica/ui/lib/utils";
import { useT } from "../../i18n";
import { ServerAddressBar } from "../../common/server-address-bar";

type Step = "instructions" | "success";

function daemonCommands() {
  return {
    setupCmd: "multica setup",
    tokenCmd: `multica login --token <YOUR_TOKEN>
multica daemon start`,
  };
}

export function ConnectRemoteDialog({ onClose }: { onClose: () => void }) {
  const [step, setStep] = useState<Step>("instructions");
  const wsId = useWorkspaceId();
  const qc = useQueryClient();
  const initialDaemonIdsRef = useRef<Set<string> | null>(null);

  // `multica setup` is one blocking command that handles config + login
  // + daemon start; the dialog passively listens for the resulting
  // `daemon:register` WS event and auto-advances to success.
  const handleDaemonRegister = useCallback(
    () => {
      if (step !== "instructions") return;
      qc.invalidateQueries({ queryKey: runtimeKeys.all(wsId) });
      setStep("success");
    },
    [step, qc, wsId],
  );
  useWSEvent("daemon:register", handleDaemonRegister);

  // Polling fallback: the WS event can be missed if the connection drops
  // briefly during daemon restart. Poll the runtime list every 3 seconds
  // and transition to success when a new daemon_id appears OR an
  // existing one comes back online.
  useEffect(() => {
    if (step !== "instructions") return;
    const poll = async () => {
      try {
        const runtimes = await api.listRuntimes({ workspace_id: wsId });
        const onlineIds = new Set(
          runtimes
            .filter((r) => r.status === "online")
            .map((r) => r.daemon_id ?? r.id),
        );
        if (initialDaemonIdsRef.current === null) {
          initialDaemonIdsRef.current = onlineIds;
          return;
        }
        const hasNew = [...onlineIds].some((id) => !initialDaemonIdsRef.current!.has(id));
        if (hasNew) {
          qc.invalidateQueries({ queryKey: runtimeKeys.all(wsId) });
          setStep("success");
        }
      } catch { /* ignore */ }
    };
    void poll();
    const id = setInterval(poll, 3000);
    return () => clearInterval(id);
  }, [step, wsId, qc]);

  return (
    <Dialog open onOpenChange={(v) => !v && onClose()}>
      <DialogContent className="flex max-h-[85vh] flex-col gap-0 p-0 sm:max-w-lg">
        {step === "instructions" && <InstructionsStep onClose={onClose} />}
        {step === "success" && (
          <SuccessStep onClose={onClose} />
        )}
      </DialogContent>
    </Dialog>
  );
}

// ---------------------------------------------------------------------------
// Copy button + code row — mirrors onboarding/CliInstallInstructions
// ---------------------------------------------------------------------------

function CopyButton({ text, ariaLabel }: { text: string; ariaLabel: string }) {
  const [copied, setCopied] = useState(false);

  useEffect(() => {
    if (!copied) return;
    const t = setTimeout(() => setCopied(false), 2000);
    return () => clearTimeout(t);
  }, [copied]);

  const handleCopy = () => {
    void copyText(text).then((ok) => {
      if (ok) setCopied(true);
    });
  };

  return (
    <button
      type="button"
      onClick={handleCopy}
      aria-label={ariaLabel}
      className="shrink-0 rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
    >
      {copied ? (
        <Check className="h-3.5 w-3.5 text-success" aria-hidden />
      ) : (
        <Copy className="h-3.5 w-3.5" aria-hidden />
      )}
    </button>
  );
}

function CommandStep({
  n,
  label,
  cmd,
  copyAria,
}: {
  n: number;
  label: string;
  cmd: string;
  copyAria: string;
}) {
  return (
    <div>
      <p className="mb-1.5 text-xs font-medium text-foreground">
        {n}. {label}
      </p>
      <div className="flex items-start gap-2 rounded-lg bg-muted px-3 py-2.5 font-mono text-sm">
        <Terminal
          className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground"
          aria-hidden
        />
        <code
          className={cn(
            "min-w-0 flex-1 break-all whitespace-pre-wrap tabular-nums",
            CODE_LIGATURE_CLASS,
          )}
        >
          {cmd}
        </code>
        <CopyButton text={cmd} ariaLabel={copyAria} />
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Step 1: Instructions
// ---------------------------------------------------------------------------

function InstructionsStep({ onClose }: { onClose: () => void }) {
  const { t } = useT("runtimes");
  const { data: serverInfo } = useQuery({
    queryKey: ["server-info"],
    queryFn: () => api.getServerInfo(),
    staleTime: 60_000,
  });

  const firstAddr = serverInfo?.addresses.find((a) => a.type === "lan") ?? serverInfo?.addresses[0];
  const serverUrl = firstAddr
    ? `http://${firstAddr.ip}:${serverInfo!.port}`
    : null;
  const cliSetupCmd = serverUrl
    ? `multica setup self-host --server-url ${serverUrl}`
    : "multica setup";
  const { tokenCmd } = daemonCommands();
  const pairingCode = serverInfo?.pairing_code;

  return (
    <>
      <DialogHeader className="px-6 pt-6 pb-2">
        <DialogTitle className="text-base text-balance">
          {t(($) => $.connect.title)}
        </DialogTitle>
        <DialogDescription className="text-xs text-balance">
          {t(($) => $.connect.description_desktop)}
        </DialogDescription>
      </DialogHeader>

      <div className="min-h-0 flex-1 overflow-y-auto px-6 py-4">
        <div className="space-y-4">
          {/* Primary flow: share address + pairing code with the other Desktop */}
          <ServerAddressBar />

          {pairingCode && (
            <div className="rounded-lg border bg-muted/40 px-4 py-3">
              <div className="mb-1 text-[11px] font-medium text-muted-foreground">
                {t(($) => $.connect.pairing_code_label)}
              </div>
              <div className="flex items-center gap-3">
                <code
                  className={cn(
                    "text-2xl font-semibold tracking-[0.25em] text-foreground",
                    CODE_LIGATURE_CLASS,
                  )}
                >
                  {pairingCode}
                </code>
                <CopyButton text={pairingCode} ariaLabel={t(($) => $.connect.copy_aria)} />
              </div>
            </div>
          )}

          <p className="text-[11px] leading-[1.55] text-muted-foreground">
            {t(($) => $.connect.desktop_steps)}
          </p>

          <LiveListening />

          {/* Fallback: CLI commands for headless servers */}
          <CliCommandsFallback setupCmd={cliSetupCmd} tokenCmd={tokenCmd} />
        </div>
      </div>

      <DialogFooter className="m-0 rounded-b-xl border-t bg-muted/30 px-6 py-3">
        <Button variant="outline" size="sm" onClick={onClose}>
          {t(($) => $.connect.cancel)}
        </Button>
      </DialogFooter>
    </>
  );
}

function CliCommandsFallback({
  setupCmd,
  tokenCmd,
}: {
  setupCmd: string;
  tokenCmd: string;
}) {
  const { t } = useT("runtimes");
  return (
    <details className="group rounded-lg border border-dashed">
      <summary className="flex cursor-pointer list-none items-center gap-1.5 px-3 py-2 text-xs font-medium text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">
        <ChevronRight
          className="h-3 w-3 transition-transform group-open:rotate-90"
          aria-hidden
        />
        {t(($) => $.connect.cli_fallback_title)}
      </summary>
      <div className="space-y-3 border-t px-3 pt-2.5 pb-3">
        <p className="text-[11px] leading-[1.55] text-muted-foreground">
          {t(($) => $.connect.cli_fallback_hint)}
        </p>
        <CommandStep
          n={1}
          label={t(($) => $.connect.step2_label)}
          cmd={setupCmd}
          copyAria={t(($) => $.connect.copy_aria)}
        />
        <CommandStep
          n={2}
          label={t(($) => $.connect.cli_token_label)}
          cmd={tokenCmd}
          copyAria={t(($) => $.connect.copy_aria)}
        />
      </div>
    </details>
  );
}

// ---------------------------------------------------------------------------
// Live-listening indicator
// ---------------------------------------------------------------------------

function LiveListening() {
  const { t } = useT("runtimes");
  return (
    <div
      className="flex items-center gap-2.5 rounded-lg border bg-muted/40 px-3 py-2.5 text-xs"
      role="status"
      aria-live="polite"
    >
      <span className="relative inline-flex shrink-0" aria-hidden>
        <span className="absolute inline-flex h-2 w-2 animate-ping rounded-full bg-success opacity-60 motion-reduce:hidden" />
        <span className="relative inline-flex h-2 w-2 rounded-full bg-success" />
      </span>
      <span className="font-medium text-foreground">
        {t(($) => $.connect.live_listening)}
      </span>
      <span className="text-muted-foreground">
        {t(($) => $.connect.live_listening_hint)}
      </span>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Step 2: Success
// ---------------------------------------------------------------------------

function SuccessStep({
  onClose,
}: {
  onClose: () => void;
}) {
  const { t } = useT("runtimes");
  return (
    <>
      <DialogHeader className="px-6 pt-6 pb-2">
        <DialogTitle className="text-base text-balance">
          {t(($) => $.connect.success_title)}
        </DialogTitle>
        <DialogDescription className="text-xs text-balance">
          {t(($) => $.connect.success_description)}
        </DialogDescription>
      </DialogHeader>

      <div className="flex flex-col items-center gap-3 px-6 py-8">
        <div
          className="flex h-12 w-12 items-center justify-center rounded-full bg-success/10"
          aria-hidden
        >
          <Check className="h-6 w-6 text-success" />
        </div>
        <p className="text-xs text-muted-foreground text-center">
          {t(($) => $.connect.success_hint)}
        </p>
      </div>

      <DialogFooter className="m-0 rounded-b-xl border-t bg-muted/30 px-6 py-3">
        <Button size="sm" onClick={onClose}>
          {t(($) => $.connect.done)}
        </Button>
      </DialogFooter>
    </>
  );
}
