import React, { useEffect, useMemo, useRef, useState } from "react";

import { Box, Button, Chip, Paper, Typography } from "@mui/material";

import { api, getApiErrorMessage } from "../api";
import { clearAuthToken, decodeJwtPayload, getAuthPersistencePreference, getAuthToken, setAuthToken } from "../auth";
import { useToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";

declare global {
  interface Window {
    google?: any;
  }
}

type MeResponse = {
  provider?: "local" | "google" | "external";
  email?: string;
  userName?: string;
  displayName?: string;
  firstName?: string;
  lastName?: string;
  googleLink?: {
    linked: boolean;
    email?: string | null;
    linkedAt?: string | null;
  } | null;
};

function loadGoogleScript(): Promise<void> {
  return new Promise((resolve, reject) => {
    if (window.google?.accounts?.id) return resolve();
    const existing = document.getElementById("google-gsi");
    if (existing) {
      existing.addEventListener("load", () => resolve(), { once: true });
      return;
    }
    const s = document.createElement("script");
    s.id = "google-gsi";
    s.src = "https://accounts.google.com/gsi/client";
    s.async = true;
    s.defer = true;
    s.onload = () => resolve();
    s.onerror = () => reject(new Error("Failed to load Google script"));
    document.head.appendChild(s);
  });
}

export default function GoogleAuthCard({ onSignedIn }: { onSignedIn?: () => void }) {
  const { toast } = useToast();
  const { t } = useI18n();
  const [token, setToken] = useState<string | null>(() => getAuthToken());
  const [me, setMe] = useState<MeResponse | null>(null);
  const [working, setWorking] = useState(false);
  const hostRef = useRef<HTMLDivElement | null>(null);

  const clientId = (process.env.REACT_APP_GOOGLE_CLIENT_ID || "").trim();
  const payload = useMemo(() => (token ? decodeJwtPayload(token) : null), [token]);
  const isRawGoogleToken = payload?.iss === "accounts.google.com" || payload?.iss === "https://accounts.google.com";

  const actionLabel = !token
    ? t("continueWithGoogle")
    : me?.provider === "local" && !me?.googleLink?.linked
      ? t("linkWithGoogle")
      : t("signInWithGoogle");

  async function refreshMe() {
    if (!getAuthToken()) {
      setMe(null);
      return;
    }
    try {
      const res = await api.get<MeResponse>("/auth/me");
      setMe(res.data);
    } catch {
      setMe(null);
    }
  }

  useEffect(() => {
    void refreshMe();
  }, [token]);

  useEffect(() => {
    if (!token || !isRawGoogleToken) return;
    let cancelled = false;
    const exchange = async () => {
      try {
        const res = await api.post<{ accessToken: string }>("/auth/google/exchange", { token });
        if (cancelled) return;
        setAuthToken(res.data.accessToken, getAuthPersistencePreference());
        setToken(res.data.accessToken);
        toast(t("googleSignedIn"), "success");
        onSignedIn?.();
      } catch {
        if (cancelled) return;
        clearAuthToken();
        setToken(null);
        toast(t("googleNotLinkedYet"), "info");
      }
    };
    void exchange();
    return () => {
      cancelled = true;
    };
  }, [token, isRawGoogleToken, onSignedIn, toast, t]);

  useEffect(() => {
    const host = hostRef.current;
    if (!clientId || !host) return;

    const shouldRenderButton = !token || isRawGoogleToken || (me?.provider === "local" && !me?.googleLink?.linked);
    host.replaceChildren();
    if (!shouldRenderButton) return;

    let active = true;
    void loadGoogleScript()
      .then(() => {
        if (!active || !window.google?.accounts?.id || !hostRef.current) return;
        hostRef.current.replaceChildren();
        window.google.accounts.id.initialize({
          client_id: clientId,
          callback: async (resp: any) => {
            const credential = resp?.credential as string | undefined;
            if (!credential) return;
            setWorking(true);
            try {
              if (me?.provider === "local") {
                const res = await api.post<{ linked: boolean; email?: string | null }>("/auth/google/link", { token: credential });
                toast(res.data?.email ? t("googleLinkedSuccessWithEmail", { email: res.data.email }) : t("googleLinkedSuccess"), "success");
                await refreshMe();
              } else {
                const res = await api.post<{ accessToken: string }>("/auth/google/exchange", { token: credential });
                setAuthToken(res.data.accessToken, getAuthPersistencePreference());
                setToken(res.data.accessToken);
                toast(t("googleSignedIn"), "success");
                onSignedIn?.();
              }
            } catch (e: any) {
              toast(getApiErrorMessage(e, t("googleAuthFailed")), "error");
            } finally {
              setWorking(false);
            }
          },
        });
        window.google.accounts.id.renderButton(hostRef.current, {
          theme: "outline",
          size: "large",
          type: "standard",
          shape: "pill",
          text: me?.provider === "local" ? "continue_with" : "signin_with",
        });
      })
      .catch(() => toast(t("googleScriptLoadFailed"), "error"));

    return () => {
      active = false;
      host.replaceChildren();
    };
  }, [clientId, me?.provider, me?.googleLink?.linked, onSignedIn, isRawGoogleToken, token, toast, t]);

  const signedInName = me?.userName || me?.displayName || [me?.firstName, me?.lastName].filter(Boolean).join(" ") || me?.email || "";

  return (
    <Paper sx={{ mt: 2, p: 2 }}>
      <Typography variant="h6" sx={{ mb: 1 }}>
        {t("googleAccountTitle")}
      </Typography>

      {!clientId && (
        <Typography sx={{ color: "text.secondary" }}>
          {t("googleSetupHint")}
        </Typography>
      )}

      {clientId && (
        <Box sx={{ display: "flex", flexDirection: "column", gap: 1.25 }}>
          <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
            <Chip size="small" label={me?.googleLink?.linked ? t("googleLinked") : t("googleAvailableToLink")} color={me?.googleLink?.linked ? "success" : "default"} variant={me?.googleLink?.linked ? "filled" : "outlined"} />
            {me?.googleLink?.linkedAt ? <Chip size="small" variant="outlined" label={t("googleLinkedDate", { date: new Date(me.googleLink.linkedAt).toLocaleDateString() })} /> : null}
          </Box>

          {!token ? (
            <Typography sx={{ color: "text.secondary" }}>
              {t("googleSignInHint")}
            </Typography>
          ) : me?.provider === "local" ? (
            <Typography sx={{ color: "text.secondary" }}>
              {me.googleLink?.linked
                ? t("googleLinkedTo", { email: me.googleLink.email || t("googleLinkedToYourAccount") })
                : t("googleBindHint")}
            </Typography>
          ) : (
            <Typography sx={{ color: "text.secondary" }}>
              {t("googleExchangeHint")}
            </Typography>
          )}

          <Box sx={{ display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 1 }}>
            <Typography variant="caption" sx={{ color: "text.secondary", fontWeight: 700, letterSpacing: 0.4, textTransform: "uppercase" }}>
              {actionLabel}
            </Typography>
            <div ref={hostRef} />
          </Box>

          <Box sx={{ display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap" }}>
            {token ? (
              <Button
                variant="outlined"
                onClick={() => {
                  clearAuthToken();
                  setToken(null);
                  setMe(null);
                  toast(t("signedOut"), "info");
                }}
              >
                {t("signOut")}
              </Button>
            ) : null}

            {me?.provider === "local" && me.googleLink?.linked ? (
              <Button
                variant="outlined"
                color="warning"
                disabled={working}
                onClick={async () => {
                  try {
                    await api.delete("/auth/google/link");
                    toast(t("googleUnlinked"), "info");
                    await refreshMe();
                  } catch (e: any) {
                    const msg = e?.response?.data || e?.message || t("googleUnlinkFailed");
                    toast(String(msg), "error");
                  }
                }}
              >
                {t("unlinkGoogle")}
              </Button>
            ) : null}
          </Box>

          {token && me?.email ? (
            <Typography variant="body2" sx={{ color: "text.secondary" }}>
              {t("signedInAs", { name: signedInName })}
            </Typography>
          ) : null}
        </Box>
      )}
    </Paper>
  );
}
