import { useEffect, useRef, useState } from "react";
import { ExternalLink, X, Check } from "lucide-react";
import { Button } from "@nous-research/ui/ui/components/button";
import { CopyButton } from "@nous-research/ui/ui/components/command-block";
import { Spinner } from "@nous-research/ui/ui/components/spinner";
import { H2 } from "@/components/NouiTypography";
import { api, type OAuthProvider, type OAuthStartResponse } from "@/lib/api";
import { Input } from "@/components/ui/input";
import { useI18n } from "@/i18n";

interface Props {
  provider: OAuthProvider;
  onClose: () => void;
  onSuccess: (msg: string) => void;
  onError: (msg: string) => void;
}

type Phase =
  | "idle"
  | "starting"
  | "awaiting_user"
  | "submitting"
  | "polling"
  | "approved"
  | "error";

export function OAuthLoginModal({ provider, onClose, onSuccess }: Props) {
  const [phase, setPhase] = useState<Phase>("starting");
  const [start, setStart] = useState<OAuthStartResponse | null>(null);
  const [pkceCode, setPkceCode] = useState("");
  const [errorMsg, setErrorMsg] = useState<string | null>(null);
  const [secondsLeft, setSecondsLeft] = useState<number | null>(null);
  const isMounted = useRef(true);
  const pollTimer = useRef<number | null>(null);
  const { t } = useI18n();

  // Initiate flow on mount
  useEffect(() => {
    isMounted.current = true;
    api
      .startOAuthLogin(provider.id)
      .then((resp) => {
        if (!isMounted.current) return;
        setStart(resp);
        setSecondsLeft(resp.expires_in);
        setPhase(resp.flow === "device_code" ? "polling" : "awaiting_user");
        if (resp.flow === "pkce") {
          window.open(resp.auth_url, "_blank", "noopener,noreferrer");
        } else {
          window.open(resp.verification_url, "_blank", "noopener,noreferrer");
        }
      })
      .catch((e) => {
        if (!isMounted.current) return;
        setPhase("error");
        setErrorMsg(`Failed to start login: ${e}`);
      });
    return () => {
      isMounted.current = false;
      if (pollTimer.current !== null) window.clearInterval(pollTimer.current);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Tick the countdown
  useEffect(() => {
    if (secondsLeft === null) return;
    if (phase === "approved" || phase === "error") return;
    const tick = window.setInterval(() => {
      if (!isMounted.current) return;
      setSecondsLeft((s) => {
        if (s !== null && s <= 1) {
          setPhase("error");
          setErrorMsg(t.oauth.sessionExpired);
          return 0;
        }
        return s !== null && s > 0 ? s - 1 : 0;
      });
    }, 1000);
    return () => window.clearInterval(tick);
  }, [secondsLeft, phase, t]);

  // Device-code: poll backend every 2s
  useEffect(() => {
    if (!start || start.flow !== "device_code" || phase !== "polling") return;
    const sid = start.session_id;
    pollTimer.current = window.setInterval(async () => {
      try {
        const resp = await api.pollOAuthSession(provider.id, sid);
        if (!isMounted.current) return;
        if (resp.status === "approved") {
          setPhase("approved");
          if (pollTimer.current !== null)
            window.clearInterval(pollTimer.current);
          onSuccess(`${provider.name} connected`);
          window.setTimeout(() => isMounted.current && onClose(), 1500);
        } else if (resp.status !== "pending") {
          setPhase("error");
          setErrorMsg(resp.error_message || `Login ${resp.status}`);
          if (pollTimer.current !== null)
            window.clearInterval(pollTimer.current);
        }
      } catch (e) {
        if (!isMounted.current) return;
        setPhase("error");
        setErrorMsg(`Polling failed: ${e}`);
        if (pollTimer.current !== null) window.clearInterval(pollTimer.current);
      }
    }, 2000);
    return () => {
      if (pollTimer.current !== null) window.clearInterval(pollTimer.current);
    };
  }, [start, phase, provider.id, provider.name, onSuccess, onClose]);

  const handleSubmitPkceCode = async () => {
    if (!start || start.flow !== "pkce") return;
    if (!pkceCode.trim()) return;
    setPhase("submitting");
    setErrorMsg(null);
    try {
      const resp = await api.submitOAuthCode(
        provider.id,
        start.session_id,
        pkceCode.trim(),
      );
      if (!isMounted.current) return;
      if (resp.ok && resp.status === "approved") {
        setPhase("approved");
        onSuccess(`${provider.name} connected`);
        window.setTimeout(() => isMounted.current && onClose(), 1500);
      } else {
        setPhase("error");
        setErrorMsg(resp.message || "Token exchange failed");
      }
    } catch (e) {
      if (!isMounted.current) return;
      setPhase("error");
      setErrorMsg(`Submit failed: ${e}`);
    }
  };

  const handleClose = async () => {
    if (start && phase !== "approved" && phase !== "error") {
      try {
        await api.cancelOAuthSession(start.session_id);
      } catch {
        // ignore
      }
    }
    onClose();
  };

  const handleBackdrop = (e: React.MouseEvent) => {
    if (e.target === e.currentTarget) handleClose();
  };

  const fmtTime = (s: number | null) => {
    if (s === null) return "";
    const m = Math.floor(s / 60);
    const r = s % 60;
    return `${m}:${String(r).padStart(2, "0")}`;
  };

  return (
    <div
      className="fixed inset-0 z-[100] flex items-center justify-center bg-background/85 backdrop-blur-sm p-4"
      onClick={handleBackdrop}
      role="dialog"
      aria-modal="true"
      aria-labelledby="oauth-modal-title"
    >
      <div className="relative w-full max-w-md border border-border bg-card shadow-2xl">
        <Button
          ghost
          size="icon"
          onClick={handleClose}
          className="absolute right-2 top-2 text-muted-foreground hover:text-foreground"
          aria-label={t.common.close}
        >
          <X />
        </Button>
        <div className="p-6 flex flex-col gap-4">
          <div>
            <H2
              id="oauth-modal-title"
              variant="sm"
              mondwest
              className="tracking-wider uppercase"
            >
              {t.oauth.connect} {provider.name}
            </H2>
            {secondsLeft !== null &&
              phase !== "approved" &&
              phase !== "error" && (
                <p className="text-xs text-muted-foreground mt-1">
                  {t.oauth.sessionExpires.replace(
                    "{time}",
                    fmtTime(secondsLeft),
                  )}
                </p>
              )}
          </div>

          {phase === "starting" && (
            <div className="flex items-center gap-3 py-6 text-sm text-muted-foreground">
              <Spinner />
              {t.oauth.initiatingLogin}
            </div>
          )}

          {start?.flow === "pkce" && phase === "awaiting_user" && (
            <>
              <ol className="text-sm space-y-2 list-decimal list-inside text-muted-foreground">
                <li>{t.oauth.pkceStep1}</li>
                <li>{t.oauth.pkceStep2}</li>
                <li>{t.oauth.pkceStep3}</li>
              </ol>
              <div className="flex flex-col gap-2">
                <Input
                  value={pkceCode}
                  onChange={(e) => setPkceCode(e.target.value)}
                  placeholder={t.oauth.pasteCode}
                  onKeyDown={(e) => e.key === "Enter" && handleSubmitPkceCode()}
                  autoFocus
                />
                <div className="flex items-center gap-2 justify-between">
                  <a
                    href={
                      (start as Extract<OAuthStartResponse, { flow: "pkce" }>)
                        .auth_url
                    }
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-xs text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
                  >
                    <ExternalLink className="h-3 w-3" />
                    {t.oauth.reOpenAuth}
                  </a>
                  <Button
                    onClick={handleSubmitPkceCode}
                    disabled={!pkceCode.trim()}
                  >
                    {t.oauth.submitCode}
                  </Button>
                </div>
              </div>
            </>
          )}

          {phase === "submitting" && (
            <div className="flex items-center gap-3 py-6 text-sm text-muted-foreground">
              <Spinner />
              {t.oauth.exchangingCode}
            </div>
          )}

          {start?.flow === "device_code" && phase === "polling" && (
            <>
              <p className="text-sm text-muted-foreground">
                {t.oauth.enterCodePrompt}
              </p>
              <div className="flex items-center justify-between gap-2 border border-border bg-secondary/30 p-4">
                <code className="font-mono-ui text-2xl tracking-widest text-foreground">
                  {
                    (
                      start as Extract<
                        OAuthStartResponse,
                        { flow: "device_code" }
                      >
                    ).user_code
                  }
                </code>
                <CopyButton
                  text={
                    (
                      start as Extract<
                        OAuthStartResponse,
                        { flow: "device_code" }
                      >
                    ).user_code
                  }
                />
              </div>
              <a
                href={
                  (
                    start as Extract<
                      OAuthStartResponse,
                      { flow: "device_code" }
                    >
                  ).verification_url
                }
                target="_blank"
                rel="noopener noreferrer"
                className="text-xs text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
              >
                <ExternalLink className="h-3 w-3" />
                {t.oauth.reOpenVerification}
              </a>
              <div className="flex items-center gap-2 text-xs text-muted-foreground border-t border-border pt-3">
                <Spinner className="text-xs" />
                {t.oauth.waitingAuth}
              </div>
            </>
          )}

          {phase === "approved" && (
            <div className="flex items-center gap-3 py-6 text-sm text-success">
              <Check className="h-5 w-5" />
              {t.oauth.connectedClosing}
            </div>
          )}

          {phase === "error" && (
            <>
              <div className="border border-destructive/30 bg-destructive/10 p-3 text-sm text-destructive">
                {errorMsg || t.oauth.loginFailed}
              </div>
              <div className="flex justify-end gap-2">
                <Button outlined onClick={handleClose}>
                  {t.common.close}
                </Button>
                <Button
                  onClick={() => {
                    if (start?.session_id) {
                      api.cancelOAuthSession(start.session_id).catch(() => {});
                    }
                    setErrorMsg(null);
                    setStart(null);
                    setPkceCode("");
                    setPhase("starting");
                    api
                      .startOAuthLogin(provider.id)
                      .then((resp) => {
                        if (!isMounted.current) return;
                        setStart(resp);
                        setSecondsLeft(resp.expires_in);
                        setPhase(
                          resp.flow === "device_code"
                            ? "polling"
                            : "awaiting_user",
                        );
                        if (resp.flow === "pkce") {
                          window.open(
                            resp.auth_url,
                            "_blank",
                            "noopener,noreferrer",
                          );
                        } else {
                          window.open(
                            resp.verification_url,
                            "_blank",
                            "noopener,noreferrer",
                          );
                        }
                      })
                      .catch((e) => {
                        if (!isMounted.current) return;
                        setPhase("error");
                        setErrorMsg(`${t.common.retry} failed: ${e}`);
                      });
                  }}
                >
                  {t.common.retry}
                </Button>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}
