import { QRCodeSVG } from "qrcode.react";
import { LoaderCircle } from "lucide-react";
import { useEffect, useState } from "react";
import { useI18n } from "../i18n";
import {
  createTokenPocketLoginRequest,
  fetchTokenPocketLoginResult,
  verifyWalletSignature,
  type TokenPocketLoginRequest,
} from "./api";
import { openWalletDeepLink, walletDownloadUrl } from "./deepLinks";
import { getInjectedEthereum, type WalletKind } from "./injected";
import { useWallet } from "./WalletProvider";
import { useWalletConnectLogin } from "./useWalletConnectLogin";
import { WalletBrandIcon } from "./WalletBrandIcon";

const pollIntervalMs = 1800;

type ModalState = "idle" | "signing" | "tpLoading" | "tpPolling";

const appWallets: { kind: WalletKind; labelKey: string }[] = [
  { kind: "tokenPocket", labelKey: "walletOpenTokenPocket" },
  { kind: "metaMask", labelKey: "walletOpenMetaMask" },
  { kind: "imToken", labelKey: "walletOpenImToken" },
];

function isMobileDevice(): boolean {
  if (typeof navigator === "undefined") return false;
  const ua = navigator.userAgent || "";
  if (
    /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(
      ua,
    )
  ) {
    return true;
  }
  // iPadOS 13+ reports a desktop "Macintosh" UA. A genuine touch-primary iPad
  // exposes a coarse pointer; a Mac (even with a touch peripheral) keeps a fine
  // pointer, so it stays on the desktop flow instead of the wallet-app jump.
  const coarsePointer =
    typeof window !== "undefined" &&
    typeof window.matchMedia === "function" &&
    window.matchMedia("(pointer: coarse)").matches;
  return /Macintosh/i.test(ua) && navigator.maxTouchPoints > 1 && coarsePointer;
}

export function WalletLoginModal() {
  const { t } = useI18n();
  const { closeLoginModal, completeLogin, loginModalOpen, signInInjected } =
    useWallet();
  const wc = useWalletConnectLogin();
  const [state, setState] = useState<ModalState>("idle");
  const [error, setError] = useState("");
  const [mobileDevice, setMobileDevice] = useState(false);
  const [hasInjected, setHasInjected] = useState(false);
  const [showOther, setShowOther] = useState(false);
  const [openingWallet, setOpeningWallet] = useState<WalletKind | null>(null);
  const [tpRequest, setTpRequest] = useState<TokenPocketLoginRequest | null>(
    null,
  );

  useEffect(() => {
    if (!loginModalOpen) return;
    setMobileDevice(isMobileDevice());
    setHasInjected(Boolean(getInjectedEthereum()));
    setShowOther(false);
    setOpeningWallet(null);
    setTpRequest(null);
    setState("idle");
    setError("");
    wc.reset();
  }, [loginModalOpen, wc]);

  useEffect(() => {
    if (!loginModalOpen || !tpRequest || state !== "tpPolling") return;

    let cancelled = false;
    const abortController = new AbortController();
    const poll = async () => {
      try {
        const result = await fetchTokenPocketLoginResult(
          tpRequest.actionId,
          abortController.signal,
        );
        if (cancelled) return;
        if (result.status === "completed") {
          const verified = await verifyWalletSignature({
            address: result.address,
            message: result.message,
            signature: result.signature,
          });
          if (cancelled) return;
          completeLogin(verified.token, verified.wallet);
          setState("idle");
          setTpRequest(null);
          return;
        }
        if (result.status === "expired" || result.status === "failed") {
          setState("idle");
          setTpRequest(null);
          setError(result.error || t("walletTpExpired"));
        }
      } catch (err) {
        if (
          !cancelled &&
          !(err instanceof DOMException && err.name === "AbortError")
        ) {
          setError(t("walletLoginFailed"));
        }
      }
    };

    void poll();
    const timer = window.setInterval(() => void poll(), pollIntervalMs);
    return () => {
      cancelled = true;
      abortController.abort();
      window.clearInterval(timer);
    };
  }, [completeLogin, loginModalOpen, state, t, tpRequest]);

  const busy = state === "signing" || state === "tpLoading";

  const close = () => {
    if (busy) return;
    closeLoginModal();
    setError("");
  };

  if (!loginModalOpen) return null;

  const withWallet = (key: string, kind: WalletKind) =>
    t(key).replace("{wallet}", t(walletNameKey(kind)));

  const signInjected = async () => {
    setError("");
    if (!getInjectedEthereum()) {
      setError(t("walletNoBrowserWalletDesc"));
      return;
    }
    setState("signing");
    await signInInjected()
      .catch((err) => {
        setError(err instanceof Error ? err.message : t("walletLoginFailed"));
      })
      .finally(() => setState("idle"));
  };

  const openApp = (kind: WalletKind) => {
    setError("");
    setOpeningWallet(kind);
    openWalletDeepLink(kind);
  };

  // TokenPocket login. The backend returns a `tpoutside://pull.activity` deep
  // link (a one-off SIGN request, not a dApp-browser link). On mobile we open
  // it directly so TokenPocket only asks for a signature and then returns to
  // THIS browser — the poll below finishes login here, no in-app browser. On
  // desktop we render it as a QR to scan from a phone.
  const startTokenPocketLogin = async () => {
    setError("");
    setState("tpLoading");
    try {
      const req = await createTokenPocketLoginRequest();
      setTpRequest(req);
      setState("tpPolling");
      if (mobileDevice) window.location.href = req.qrUrl;
    } catch {
      setState("idle");
      setError(t("walletTpQrFailed"));
    }
  };

  return (
    <div
      className="fixed inset-0 z-[120] flex items-end justify-center bg-black/70 px-3 pb-3 pt-10 backdrop-blur-sm md:items-center md:p-6"
      role="dialog"
      aria-modal="true"
      aria-labelledby="wallet-login-title"
    >
      <div className="max-h-[92dvh] w-full max-w-[520px] overflow-y-auto rounded-3xl border border-white/10 bg-[#17171d] p-5 shadow-2xl shadow-black/70 md:p-6">
        <div className="flex items-start justify-between gap-4">
          <div>
            <h2
              id="wallet-login-title"
              className="text-xl font-semibold text-white"
            >
              {t("walletLoginTitle")}
            </h2>
            <p className="mt-2 text-sm leading-6 text-neutral-400">
              {t("walletLoginDesc")}
            </p>
          </div>
          <button
            type="button"
            onClick={close}
            className="rounded-full border border-white/10 px-3 py-1.5 text-sm text-neutral-300 transition hover:border-ark-gold/50 hover:text-ark-gold"
          >
            {t("close")}
          </button>
        </div>

        <div className="mt-5 grid gap-3">
          {/* Browser wallet: sign directly with the injected provider — the
              reliable path for a BNB-chain extension (desktop) or a wallet's
              in-app browser. No WalletConnect relay involved. */}
          {!mobileDevice || hasInjected ? (
            <button
              type="button"
              onClick={() => void signInjected()}
              disabled={busy}
              className="flex items-center justify-center gap-2 rounded-2xl bg-ark-gold px-4 py-4 text-base font-bold text-black transition hover:bg-ark-gold2 disabled:cursor-wait disabled:opacity-70"
            >
              {state === "signing"
                ? t("walletSigning")
                : mobileDevice
                  ? t("walletUseCurrent")
                  : t("walletInjected")}
            </button>
          ) : null}

          {/* TokenPocket login — universal path that returns to this browser. */}
          <div className="grid gap-2 rounded-2xl border border-white/10 bg-white/[0.02] p-4">
            <p className="text-sm font-semibold text-neutral-100">
              {t("walletTokenPocketLogin")}
            </p>
            <p className="text-xs leading-5 text-neutral-400">
              {mobileDevice
                ? t("walletTpMobileDesc")
                : t("walletTokenPocketQrDesc")}
            </p>
            {!tpRequest ? (
              <button
                type="button"
                onClick={() => void startTokenPocketLogin()}
                disabled={state === "tpLoading"}
                className="mt-1 inline-flex items-center justify-center gap-2 justify-self-start rounded-full bg-ark-gold px-4 py-2 text-sm font-semibold text-black transition hover:bg-ark-gold2 disabled:cursor-wait disabled:opacity-70"
              >
                <WalletBrandIcon kind="tokenPocket" size={20} />
                {state === "tpLoading"
                  ? t("loading")
                  : mobileDevice
                    ? t("walletTpLoginBtn")
                    : t("walletGenerateQr")}
              </button>
            ) : mobileDevice ? (
              <div className="mt-1 grid gap-2 rounded-2xl border border-dashed border-white/15 bg-white/[0.03] px-4 py-3">
                <p className="flex items-center gap-2 text-xs leading-5 text-neutral-300">
                  <LoaderCircle className="h-4 w-4 animate-spin text-ark-gold" />
                  {t("walletTpWaiting")}
                </p>
                <button
                  type="button"
                  onClick={() => {
                    window.location.href = tpRequest.qrUrl;
                  }}
                  className="justify-self-start rounded-full border border-ark-gold/40 px-3 py-1.5 text-xs font-semibold text-ark-gold transition hover:bg-ark-gold/10"
                >
                  {t("walletTpReopen")}
                </button>
              </div>
            ) : (
              <div className="mt-1 grid place-items-center gap-2 rounded-2xl bg-white p-4 text-center">
                <QRCodeSVG value={tpRequest.qrUrl} size={180} level="M" />
                <p className="text-xs font-medium text-neutral-700">
                  {t("walletQrUseAnotherDevice")}
                </p>
              </div>
            )}
          </div>

          {/* Other methods: open a wallet app (mobile) and WalletConnect QR. */}
          <div className="rounded-2xl border border-dashed border-white/15">
            <button
              type="button"
              onClick={() => setShowOther((value) => !value)}
              className="flex w-full items-center justify-between px-4 py-3 text-left text-sm font-semibold text-ark-gold transition hover:text-ark-gold2"
            >
              <span>{t("walletOtherMethods")}</span>
              <span>{showOther ? "−" : "+"}</span>
            </button>

            {showOther ? (
              <div className="grid gap-4 px-4 pb-4">
                {mobileDevice && !hasInjected ? (
                  <div className="grid gap-2">
                    <p className="text-sm font-semibold text-neutral-200">
                      {t("walletOpenWalletApp")}
                    </p>
                    {appWallets.map((option) => (
                      <button
                        key={option.kind}
                        type="button"
                        onClick={() => openApp(option.kind)}
                        className="flex items-center gap-3 rounded-2xl border border-white/10 bg-[#20202a] px-4 py-3 text-left text-sm font-semibold text-neutral-100 transition hover:border-ark-gold/50 hover:bg-ark-gold/10"
                      >
                        <WalletBrandIcon kind={option.kind} />
                        <span>{t(option.labelKey)}</span>
                      </button>
                    ))}
                    {openingWallet ? (
                      <div className="grid gap-2 rounded-2xl border border-dashed border-white/15 bg-white/[0.03] px-4 py-3 text-xs leading-5 text-neutral-400">
                        <p>{withWallet("walletOpening", openingWallet)}</p>
                        <p>{t("walletAppNotInstalled")}</p>
                        <div className="flex flex-wrap gap-2 pt-1">
                          <a
                            href={walletDownloadUrl(openingWallet)}
                            target="_blank"
                            rel="noopener noreferrer"
                            className="rounded-full border border-ark-gold/40 px-3 py-1.5 font-semibold text-ark-gold transition hover:bg-ark-gold/10"
                          >
                            {withWallet("walletDownloadApp", openingWallet)}
                          </a>
                          <button
                            type="button"
                            onClick={() => openApp(openingWallet)}
                            className="rounded-full border border-white/15 px-3 py-1.5 font-semibold text-neutral-200 transition hover:border-ark-gold/40 hover:text-ark-gold"
                          >
                            {t("walletRetry")}
                          </button>
                        </div>
                      </div>
                    ) : null}
                  </div>
                ) : null}

                {/* MetaMask / imToken QR via WalletConnect — needs a real id. */}
                <div
                  className={
                    mobileDevice && !hasInjected
                      ? "grid gap-2 border-t border-white/10 pt-4"
                      : "grid gap-2"
                  }
                >
                  <p className="text-sm font-semibold text-neutral-200">
                    {t("walletRainbowFallback")}
                  </p>
                  <p className="text-xs leading-5 text-neutral-400">
                    {t("walletRainbowFallbackDesc")}
                  </p>
                  {wc.available ? (
                    <>
                      <button
                        type="button"
                        onClick={() => wc.start()}
                        disabled={wc.state !== "idle"}
                        className="justify-self-start rounded-full border border-ark-gold/50 px-4 py-2 text-sm font-semibold text-ark-gold transition hover:bg-ark-gold/10 disabled:cursor-wait disabled:opacity-70"
                      >
                        {wc.state === "connecting"
                          ? t("walletConnecting")
                          : wc.state === "signing"
                            ? t("walletSigning")
                            : t("walletOpenRainbow")}
                      </button>
                      <p className="text-xs leading-5 text-amber-300/80">
                        {t("walletNetworkWarning")}
                      </p>
                    </>
                  ) : (
                    <p className="rounded-xl border border-white/10 bg-white/[0.03] px-3 py-2 text-xs leading-5 text-neutral-500">
                      {t("walletRainbowUnavailable")}
                    </p>
                  )}
                </div>
              </div>
            ) : null}
          </div>
        </div>

        {error || wc.error ? (
          <p className="mt-4 rounded-2xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-200">
            {error || wc.error}
          </p>
        ) : null}
      </div>
    </div>
  );
}

function walletNameKey(kind: WalletKind): string {
  if (kind === "tokenPocket") return "walletTokenPocket";
  if (kind === "metaMask") return "walletMetaMask";
  return "walletImToken";
}
