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

import {
  Alert,
  Box,
  Button,
  Checkbox,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  FormControlLabel,
  IconButton,
  List,
  ListItem,
  ListItemSecondaryAction,
  ListItemText,
  Paper,
  TextField,
  Typography,
} from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";

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

type Status = { enabled: boolean; enabledAtUtc: string | null };
type SetupResponse = { manualEntryKey: string; qrCodeDataUrl: string };
type RecoveryCodesResponse = { recoveryCodes: string[] };
type TrustedDevice = {
  id: number;
  deviceLabel: string | null;
  createdAtUtc: string;
  lastSeenAtUtc: string;
  expiresAtUtc: string;
  isCurrentDevice: boolean;
};

type Flow =
  | "closed"
  | "enable-password"
  | "enable-qr"
  | "enable-recovery"
  | "disable-password"
  | "regenerate-password"
  | "regenerate-recovery"
  | "revoke-all-confirm";

function apiErrorMessage(e: any, t: (k: any) => string) {
  if (e?.response?.status === 429) return t("twoFactorRateLimited");
  return getApiErrorMessage(e, t("twoFactorGenericError"));
}

export default function TwoFactorSettingsCard() {
  const { toast } = useToast();
  const { t } = useI18n();
  const [status, setStatus] = useState<Status | null>(null);
  const [flow, setFlow] = useState<Flow>("closed");
  const [password, setPassword] = useState("");
  const [code, setCode] = useState("");
  const [setup, setSetup] = useState<SetupResponse | null>(null);
  const [recoveryCodes, setRecoveryCodes] = useState<string[]>([]);
  const [savedConfirmed, setSavedConfirmed] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [devices, setDevices] = useState<TrustedDevice[]>([]);
  const [devicesLoading, setDevicesLoading] = useState(false);
  const [devicesError, setDevicesError] = useState<string | null>(null);

  const loadStatus = useCallback(() => {
    api.get<Status>("/auth/2fa/status").then((r) => setStatus(r.data)).catch(() => setStatus(null));
  }, []);

  const loadDevices = useCallback(() => {
    setDevicesLoading(true);
    setDevicesError(null);
    api
      .get<TrustedDevice[]>("/auth/2fa/trusted-devices")
      .then((r) => setDevices(r.data))
      .catch((e) => setDevicesError(apiErrorMessage(e, t)))
      .finally(() => setDevicesLoading(false));
  }, [t]);

  useEffect(() => { loadStatus(); loadDevices(); }, [loadDevices, loadStatus]);

  async function revokeDevice(id: number) {
    try {
      await api.delete(`/auth/2fa/trusted-devices/${id}`);
      loadDevices();
    } catch (e: any) {
      setDevicesError(apiErrorMessage(e, t));
    }
  }

  async function revokeAllDevices() {
    try {
      await api.post("/auth/2fa/trusted-devices/revoke-all");
      toast(t("twoFactorTrustedDevicesRevokedAll"), "success");
      closeFlow();
      loadDevices();
    } catch (e: any) {
      setError(apiErrorMessage(e, t));
    }
  }

  function closeFlow() {
    setFlow("closed");
    setPassword("");
    setCode("");
    setSetup(null);
    setRecoveryCodes([]);
    setSavedConfirmed(false);
    setError(null);
  }

  async function submitPassword() {
    setLoading(true);
    setError(null);
    try {
      if (flow === "enable-password") {
        const res = await api.post<SetupResponse>("/auth/2fa/setup", { currentPassword: password });
        setSetup(res.data);
        setPassword("");
        setFlow("enable-qr");
      } else if (flow === "disable-password") {
        await api.post("/auth/2fa/disable", { currentPassword: password });
        toast(t("twoFactorDisabledSuccess"), "success");
        closeFlow();
        loadStatus();
      } else if (flow === "regenerate-password") {
        const res = await api.post<RecoveryCodesResponse>("/auth/2fa/recovery-codes/regenerate", { currentPassword: password });
        setRecoveryCodes(res.data.recoveryCodes);
        setPassword("");
        setFlow("regenerate-recovery");
      }
    } catch (e: any) {
      setError(e?.response?.status === 400 || e?.response?.status === 401 ? t("twoFactorWrongPassword") : apiErrorMessage(e, t));
    } finally {
      setLoading(false);
    }
  }

  async function submitCode() {
    setLoading(true);
    setError(null);
    try {
      const res = await api.post<RecoveryCodesResponse>("/auth/2fa/verify-setup", { code });
      setRecoveryCodes(res.data.recoveryCodes);
      setCode("");
      setFlow("enable-recovery");
    } catch (e: any) {
      setError(e?.response?.status === 401 ? t("twoFactorInvalidCode") : apiErrorMessage(e, t));
    } finally {
      setLoading(false);
    }
  }

  function finishRecovery() {
    toast(flow === "enable-recovery" ? t("twoFactorEnabledSuccess") : t("twoFactorRegenerateSuccess"), "success");
    closeFlow();
    loadStatus();
  }

  function copyRecoveryCodes() {
    void navigator.clipboard.writeText(recoveryCodes.join("\n"));
    toast(t("twoFactorCodesCopied"), "info");
  }

  function downloadRecoveryCodes() {
    const blob = new Blob([recoveryCodes.join("\n") + "\n"], { type: "text/plain" });
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = "jobbjakt-recovery-codes.txt";
    document.body.appendChild(link);
    link.click();
    link.remove();
    window.URL.revokeObjectURL(url);
  }

  const isPasswordStep = flow === "enable-password" || flow === "disable-password" || flow === "regenerate-password";
  const isRecoveryStep = flow === "enable-recovery" || flow === "regenerate-recovery";

  return (
    <Paper sx={{ mt: 2, p: 2.5, borderRadius: 4, border: "none", boxShadow: "0px 1px 2px 0px rgba(15,23,42,0.04), 0px 8px 24px -12px rgba(15,23,42,0.12)" }}>
      <Typography variant="h6" sx={{ mb: 1 }}>
        {t("twoFactorSectionTitle")}
      </Typography>

      {status ? (
        <Typography sx={{ color: "text.secondary", mb: 1.5 }}>
          {status.enabled
            ? t("twoFactorStatusEnabled", { date: status.enabledAtUtc ? new Date(status.enabledAtUtc).toLocaleDateString() : "" })
            : t("twoFactorStatusDisabled")}
        </Typography>
      ) : null}

      <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
        {!status?.enabled ? (
          <Button variant="contained" onClick={() => setFlow("enable-password")}>
            {t("twoFactorEnableButton")}
          </Button>
        ) : (
          <>
            <Button variant="outlined" color="warning" onClick={() => setFlow("disable-password")}>
              {t("twoFactorDisableButton")}
            </Button>
            <Button variant="outlined" onClick={() => setFlow("regenerate-password")}>
              {t("twoFactorRegenerateButton")}
            </Button>
          </>
        )}
      </Box>

      {status?.enabled ? (
        <Box sx={{ mt: 2 }}>
          <Divider sx={{ mb: 1.5 }} />
          <Typography variant="subtitle1" sx={{ fontWeight: 700, mb: 0.5 }}>
            {t("twoFactorTrustedDevicesTitle")}
          </Typography>
          {devicesError ? <Alert severity="error" role="alert" sx={{ mb: 1 }}>{devicesError}</Alert> : null}
          {!devicesLoading && devices.length === 0 && !devicesError ? (
            <Typography sx={{ color: "text.secondary", mb: 1 }}>{t("twoFactorTrustedDevicesEmpty")}</Typography>
          ) : null}
          {devices.length > 0 ? (
            <List dense disablePadding>
              {devices.map((d) => (
                <ListItem key={d.id} divider>
                  <ListItemText
                    primary={
                      <>
                        {d.deviceLabel || t("twoFactorTrustedDeviceUnknown")}
                        {d.isCurrentDevice ? (
                          <Typography component="span" variant="caption" sx={{ ml: 1, color: "primary.main", fontWeight: 700 }}>
                            {t("twoFactorTrustedDeviceCurrent")}
                          </Typography>
                        ) : null}
                      </>
                    }
                    secondary={t("twoFactorTrustedDeviceMeta", {
                      lastSeen: new Date(d.lastSeenAtUtc).toLocaleDateString(),
                      expires: new Date(d.expiresAtUtc).toLocaleDateString(),
                    })}
                  />
                  <ListItemSecondaryAction>
                    <IconButton edge="end" aria-label={t("twoFactorRevokeDevice")} onClick={() => revokeDevice(d.id)}>
                      <DeleteIcon fontSize="small" />
                    </IconButton>
                  </ListItemSecondaryAction>
                </ListItem>
              ))}
            </List>
          ) : null}
          {devices.length > 0 ? (
            <Button variant="text" color="warning" size="small" sx={{ mt: 1 }} onClick={() => setFlow("revoke-all-confirm")}>
              {t("twoFactorRevokeAllDevices")}
            </Button>
          ) : null}
        </Box>
      ) : null}

      <Dialog open={flow !== "closed"} onClose={isRecoveryStep ? undefined : closeFlow} maxWidth="sm" fullWidth>
        {isPasswordStep && (
          <Box component="form" onSubmit={(e) => { e.preventDefault(); void submitPassword(); }}>
            <DialogTitle>{t("twoFactorPasswordPrompt")}</DialogTitle>
            <DialogContent>
              {flow === "disable-password" ? <Alert severity="warning" sx={{ mb: 2 }}>{t("twoFactorDisableWarning")}</Alert> : null}
              {flow === "regenerate-password" ? <Alert severity="warning" sx={{ mb: 2 }}>{t("twoFactorRegenerateWarning")}</Alert> : null}
              {error ? <Alert severity="error" role="alert" sx={{ mb: 2 }}>{error}</Alert> : null}
              <TextField
                label={t("twoFactorPasswordLabel")}
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                autoComplete="current-password"
                autoFocus
                fullWidth
              />
            </DialogContent>
            <DialogActions>
              <Button type="button" onClick={closeFlow} disabled={loading}>{t("cancel")}</Button>
              <Button type="submit" variant="contained" disabled={loading || !password}>
                {t("twoFactorContinue")}
              </Button>
            </DialogActions>
          </Box>
        )}

        {flow === "enable-qr" && setup && (
          <Box component="form" onSubmit={(e) => { e.preventDefault(); void submitCode(); }}>
            <DialogTitle>{t("twoFactorSetupTitle")}</DialogTitle>
            <DialogContent>
              <Typography variant="body2" sx={{ color: "text.secondary", mb: 2 }}>
                {t("twoFactorSetupHint")}
              </Typography>
              <Box sx={{ display: "flex", justifyContent: "center", mb: 2 }}>
                <img src={setup.qrCodeDataUrl} alt={t("twoFactorSetupTitle")} width={200} height={200} />
              </Box>
              <TextField
                label={t("twoFactorManualKeyLabel")}
                value={setup.manualEntryKey}
                fullWidth
                sx={{ mb: 1 }}
                InputProps={{
                  readOnly: true,
                  endAdornment: (
                    <Button
                      size="small"
                      onClick={() => {
                        void navigator.clipboard.writeText(setup.manualEntryKey);
                        toast(t("twoFactorKeyCopied"), "info");
                      }}
                    >
                      {t("twoFactorCopyKey")}
                    </Button>
                  ),
                }}
              />
              <Typography variant="body2" sx={{ color: "text.secondary", mt: 2, mb: 1 }}>
                {t("twoFactorConfirmCodeHint")}
              </Typography>
              {error ? <Alert severity="error" role="alert" sx={{ mb: 2 }}>{error}</Alert> : null}
              <TextField
                label={t("twoFactorConfirmCodeLabel")}
                value={code}
                onChange={(e) => setCode(e.target.value)}
                autoComplete="one-time-code"
                fullWidth
              />
            </DialogContent>
            <DialogActions>
              <Button type="button" onClick={closeFlow} disabled={loading}>{t("cancel")}</Button>
              <Button type="submit" variant="contained" disabled={loading || !code.trim()}>
                {t("twoFactorConfirmButton")}
              </Button>
            </DialogActions>
          </Box>
        )}

        {isRecoveryStep && (
          <>
            <DialogTitle role="alert">{t("twoFactorRecoveryTitle")}</DialogTitle>
            <DialogContent>
              <Alert severity="warning" sx={{ mb: 2 }}>{t("twoFactorRecoveryHint")}</Alert>
              <Box
                component="ul"
                sx={{ fontFamily: "monospace", fontSize: 16, p: 1.5, borderRadius: 2, backgroundColor: "background.default", border: "1px solid", borderColor: "divider", listStyle: "none", m: 0, mb: 2 }}
              >
                {recoveryCodes.map((rc) => (
                  <li key={rc}>{rc}</li>
                ))}
              </Box>
              <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", mb: 2 }}>
                <Button variant="outlined" onClick={copyRecoveryCodes}>{t("twoFactorCopyAll")}</Button>
                <Button variant="outlined" onClick={downloadRecoveryCodes}>{t("twoFactorDownload")}</Button>
              </Box>
              <FormControlLabel
                control={<Checkbox checked={savedConfirmed} onChange={(e) => setSavedConfirmed(e.target.checked)} />}
                label={t("twoFactorSavedConfirm")}
              />
            </DialogContent>
            <DialogActions>
              <Button variant="contained" disabled={!savedConfirmed} onClick={finishRecovery}>
                {t("twoFactorDone")}
              </Button>
            </DialogActions>
          </>
        )}

        {flow === "revoke-all-confirm" && (
          <>
            <DialogTitle>{t("twoFactorRevokeAllConfirmTitle")}</DialogTitle>
            <DialogContent>
              {error ? <Alert severity="error" role="alert" sx={{ mb: 2 }}>{error}</Alert> : null}
              <Typography>{t("twoFactorRevokeAllConfirmBody")}</Typography>
            </DialogContent>
            <DialogActions>
              <Button type="button" onClick={closeFlow}>{t("cancel")}</Button>
              <Button variant="contained" color="warning" onClick={revokeAllDevices}>
                {t("twoFactorRevokeAllDevices")}
              </Button>
            </DialogActions>
          </>
        )}
      </Dialog>
    </Paper>
  );
}
