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

import { Box, Button, Chip, Paper, Typography } from "@mui/material";
import { PublicClientApplication } from "@azure/msal-browser";

import { api, getApiErrorMessage } from "../api";
import { clearAuthClientState, getAuthPersistencePreference } from "../auth";
import { useToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";

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

let msalInstance: PublicClientApplication | null = null;
function getMsalInstance(clientId: string): PublicClientApplication {
  msalInstance ??= new PublicClientApplication({
    auth: { clientId, authority: "https://login.microsoftonline.com/common", redirectUri: window.location.origin },
  });
  return msalInstance;
}

export default function MicrosoftAuthCard({ onSignedIn }: { onSignedIn?: () => void }) {
  const { toast } = useToast();
  const { t } = useI18n();
  const [me, setMe] = useState<MeResponse | null>(null);
  const [working, setWorking] = useState(false);

  const clientId = (process.env.REACT_APP_MICROSOFT_CLIENT_ID || "").trim();
  const signedIn = Boolean(me?.provider);
  const actionLabel = !signedIn
    ? t("continueWithMicrosoft")
    : me?.provider === "local" && !me?.microsoftLink?.linked
      ? t("linkWithMicrosoft")
      : t("signInWithMicrosoft");

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

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

  useEffect(() => {
    const onAuthChanged = () => { void refreshMe(); };
    window.addEventListener("auth-changed", onAuthChanged);
    return () => window.removeEventListener("auth-changed", onAuthChanged);
  }, []);

  async function handleSignIn() {
    if (!clientId) return;
    setWorking(true);
    try {
      const msal = getMsalInstance(clientId);
      await msal.initialize();
      const result = await msal.loginPopup({ scopes: ["openid", "profile", "email"] });
      const idToken = result.idToken;
      if (!idToken) throw new Error(t("microsoftAuthFailed"));

      if (me?.provider === "local") {
        const res = await api.post<{ linked: boolean; email?: string | null }>("/auth/microsoft/link", { token: idToken, rememberMe: getAuthPersistencePreference() === "local" });
        toast(res.data?.email ? t("microsoftLinkedSuccessWithEmail", { email: res.data.email }) : t("microsoftLinkedSuccess"), "success");
        await refreshMe();
      } else {
        await api.post("/auth/microsoft/exchange", { token: idToken, rememberMe: getAuthPersistencePreference() === "local" });
        window.dispatchEvent(new Event("auth-changed"));
        toast(t("microsoftSignedIn"), "success");
        onSignedIn?.();
      }
    } catch (e: any) {
      toast(getApiErrorMessage(e, t("microsoftAuthFailed")), "error");
    } finally {
      setWorking(false);
    }
  }

  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("microsoftAccountTitle")}
      </Typography>

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

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

          {!signedIn ? (
            <Typography sx={{ color: "text.secondary" }}>
              {t("microsoftSignInHint")}
            </Typography>
          ) : me?.provider === "local" ? (
            <Typography sx={{ color: "text.secondary" }}>
              {me.microsoftLink?.linked
                ? t("microsoftLinkedTo", { email: me.microsoftLink.email || t("microsoftLinkedToYourAccount") })
                : t("microsoftBindHint")}
            </Typography>
          ) : (
            <Typography sx={{ color: "text.secondary" }}>
              {t("microsoftExchangeHint")}
            </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>
            <Button variant="outlined" disabled={working} onClick={() => void handleSignIn()}>
              {actionLabel}
            </Button>
          </Box>

          <Box sx={{ display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap" }}>
            {signedIn ? (
              <Button
                variant="outlined"
                onClick={() => {
                  void api.post("/auth/logout").catch(() => undefined).finally(() => {
                    clearAuthClientState();
                    setMe(null);
                    toast(t("signedOut"), "info");
                  });
                }}
              >
                {t("signOut")}
              </Button>
            ) : null}

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

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