import { useCallback, useEffect, useState } from "react";
import { useI18n } from "../i18n";
import {
  getConnectedInjectedAddress,
  getInjectedWallet,
  signInWithInjectedWallet,
  type WalletKind,
} from "./injected";
import { shortenAddress, useWallet } from "./WalletProvider";

const AUTO_LOGIN_PARAM = "autoLogin";
const ETHEREUM_WAIT_MS = 8000;
const ETHEREUM_POLL_MS = 200;

type AutoLoginRequest = {
  kind: WalletKind;
  ready: boolean;
  address: string | null;
  signing: boolean;
  error: string;
};

function parseKind(value: string | null): WalletKind | null {
  if (value === "tokenPocket" || value === "metaMask" || value === "imToken") {
    return value;
  }
  return null;
}

function stripAutoLoginParam(): void {
  const url = new URL(window.location.href);
  url.searchParams.delete(AUTO_LOGIN_PARAM);
  const qs = url.searchParams.toString();
  const next = url.pathname + (qs ? `?${qs}` : "") + url.hash;
  window.history.replaceState({}, "", next);
}

function waitForInjected(kind: WalletKind): Promise<boolean> {
  return new Promise((resolve) => {
    const start = Date.now();
    const tick = () => {
      if (getInjectedWallet(kind)) {
        resolve(true);
        return;
      }
      if (Date.now() - start >= ETHEREUM_WAIT_MS) {
        resolve(false);
        return;
      }
      window.setTimeout(tick, ETHEREUM_POLL_MS);
    };
    tick();
  });
}

/**
 * When the page is opened via a `?autoLogin=<wallet>` deeplink (typically from
 * inside TokenPocket / imToken in-app browsers), show an explicit verification
 * prompt first. The wallet signature and backend verification only start after
 * the user taps the verification button, so Chrome -> wallet handoff never logs
 * in silently from a cached in-app-browser session.
 */
export function AutoInjectedLogin() {
  const { t } = useI18n();
  const { completeLogin, status } = useWallet();
  const [request, setRequest] = useState<AutoLoginRequest | null>(null);

  useEffect(() => {
    if (typeof window === "undefined") return;
    const params = new URLSearchParams(window.location.search);
    const kind = parseKind(params.get(AUTO_LOGIN_PARAM));
    if (!kind) return;
    if (status === "loading") return;

    stripAutoLoginParam();
    if (status === "loggedIn") {
      setRequest(null);
      return;
    }

    let cancelled = false;
    setRequest({
      kind,
      ready: false,
      address: null,
      signing: false,
      error: "",
    });

    void waitForInjected(kind).then(async (ready) => {
      if (cancelled) return;
      if (!ready) {
        setRequest((current) =>
          current?.kind === kind
            ? { ...current, ready: false, error: t("walletNoBrowserWallet") }
            : current,
        );
        return;
      }

      const address = await getConnectedInjectedAddress(kind);
      if (cancelled) return;
      setRequest((current) =>
        current?.kind === kind
          ? { ...current, ready: true, address, error: "" }
          : current,
      );
    });

    return () => {
      cancelled = true;
    };
  }, [status, t]);

  const verifyAddress = useCallback(async () => {
    if (!request || !request.ready || request.signing) return;

    setRequest((current) =>
      current ? { ...current, signing: true, error: "" } : current,
    );
    try {
      const res = await signInWithInjectedWallet(request.kind);
      completeLogin(res.token, res.wallet);
      setRequest(null);
    } catch (err) {
      const message =
        err instanceof Error ? err.message : t("walletLoginFailed");
      setRequest((current) =>
        current
          ? {
              ...current,
              signing: false,
              error: message || t("walletLoginFailed"),
            }
          : current,
      );
      // eslint-disable-next-line no-console
      console.warn("[wallet-autologin] verification failed", err);
    }
  }, [completeLogin, request, t]);

  if (!request) return null;

  const addressLabel = request.address
    ? shortenAddress(request.address)
    : t("walletVerifyAddressUnknown");

  return (
    <div
      className="fixed inset-0 z-[130] flex items-end justify-center bg-black/75 px-3 pb-3 pt-10 backdrop-blur-sm md:items-center md:p-6"
      role="dialog"
      aria-modal="true"
      aria-labelledby="wallet-verify-title"
    >
      <div className="w-full max-w-[420px] rounded-3xl border border-white/10 bg-[#17171d] p-5 shadow-2xl shadow-black/70 md:p-6">
        <p className="text-xs font-semibold uppercase tracking-[0.24em] text-ark-gold">
          {t(walletNameKey(request.kind))}
        </p>
        <h2
          id="wallet-verify-title"
          className="mt-3 text-xl font-semibold text-white"
        >
          {t("walletVerifyAddressTitle")}
        </h2>
        <p className="mt-2 text-sm leading-6 text-neutral-400">
          {t("walletVerifyAddressDesc")}
        </p>

        <div className="mt-5 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3">
          <p className="text-xs text-neutral-500">
            {t("walletDetectedAddress")}
          </p>
          <p className="mt-1 break-all font-mono text-sm text-neutral-100">
            {addressLabel}
          </p>
        </div>

        {request.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">
            {request.error}
          </p>
        ) : null}

        <button
          type="button"
          onClick={verifyAddress}
          disabled={!request.ready || request.signing}
          className="mt-5 w-full rounded-full bg-ark-gold px-4 py-3 text-sm font-bold text-black transition hover:bg-ark-gold2 disabled:cursor-wait disabled:opacity-70"
        >
          {request.signing
            ? t("walletSigning")
            : request.ready
              ? t("walletVerifyAddressButton")
              : t("walletConnecting")}
        </button>
      </div>
    </div>
  );
}

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