import { useState, useRef } from "react";
import { motion, useReducedMotion } from "framer-motion";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import QRCode from "qrcode";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import { useAuth } from "../../context/AuthContext";
import { useAlert } from "../../context/AlertContext";
import apiFetch from "../../utils/api";
import { iconBadgeSx } from "../../theme";
import { Card, Button, Modal, Field, TextField } from "../../ui";
import useDialogScrollLock from "../../ui/useDialogScrollLock";

const API_BASE = "/api/admin";

// Copy helper. navigator.clipboard is SECURE-CONTEXT ONLY (undefined over plain
// HTTP on a LAN), so we fall back to the legacy execCommand path — which works
// in insecure contexts — and report whether the copy actually succeeded. The
// caller MUST gate its success toast on the returned boolean (otherwise it lies
// to the user about copying 2FA codes / the TOTP secret).
async function copyToClipboard(text: string): Promise<boolean> {
  try {
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(text);
      return true;
    }
  } catch {
    // fall through to the legacy path
  }
  try {
    const ta = document.createElement("textarea");
    ta.value = text;
    ta.style.position = "fixed";
    ta.style.opacity = "0";
    document.body.appendChild(ta);
    ta.select();
    const ok = document.execCommand("copy");
    document.body.removeChild(ta);
    return ok;
  } catch {
    return false;
  }
}

interface DashProfileProps {
  totpEnabled: boolean;
  totpLoading: boolean;
  totpSubmitting: boolean;
  onStart2FASetup: () => void;
  onConfirm2FA: () => void;
  onDisable2FA: () => void;
  totpSecret: string | null;
  totpQrUri: string | null;
  totpCode: string;
  setTotpCode: (code: string) => void;
  backupCodes: string[] | null;
  setBackupCodes: (codes: string[] | null) => void;
  show2FASetup: boolean;
  setShow2FASetup: (show: boolean) => void;
  show2FADisable: boolean;
  setShow2FADisable: (show: boolean) => void;
  disableCode: string;
  setDisableCode: (code: string) => void;
}

interface ProfileFormData {
  username: string;
  email: string;
  new_password: string;
  current_password: string;
  first_name: string;
  last_name: string;
}

const EditIcon = (
  <svg
    width="14"
    height="14"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
    <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
  </svg>
);

const CopyIcon = (
  <svg
    width="14"
    height="14"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
    <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
  </svg>
);

export default function DashProfile({
  totpEnabled,
  totpLoading,
  totpSubmitting,
  onStart2FASetup,
  onConfirm2FA,
  onDisable2FA,
  totpSecret,
  totpQrUri,
  totpCode,
  setTotpCode,
  backupCodes,
  setBackupCodes,
  show2FASetup,
  setShow2FASetup,
  show2FADisable,
  setShow2FADisable,
  disableCode,
  setDisableCode,
}: DashProfileProps) {
  const { user, updateUser } = useAuth();
  const alert = useAlert();
  const queryClient = useQueryClient();
  const reduce = useReducedMotion();
  const totpSetupRef = useRef<HTMLInputElement>(null);

  // The 2FA setup dialog is bespoke (multi-step: setup → backup codes) and
  // locks <html> scroll like the kit dialogs.
  useDialogScrollLock(show2FASetup);

  // Generate the enrollment QR LOCALLY from the otpauth URI. Never send the
  // URI to an external QR service: the production CSP (img-src) blocks it and
  // it would leak the TOTP secret to a third party. A data: URL is allowed by
  // the CSP. Derived via useQuery (not an effect) per repo conventions.
  const { data: totpQrDataUrl, isError: totpQrFailed } = useQuery({
    queryKey: ["totp", "qr", totpQrUri],
    enabled: !!totpQrUri,
    staleTime: Infinity,
    // The URI embeds the TOTP secret — drop it from the cache as soon as the
    // enrollment UI unmounts instead of keeping it for the default 5-min GC.
    gcTime: 0,
    retry: false,
    queryFn: async () => {
      try {
        return await QRCode.toDataURL(totpQrUri!, { width: 200, margin: 2 });
      } catch (err) {
        console.error("DashProfile: generování QR kódu selhalo", err);
        throw err;
      }
    },
  });

  const [showModal, setShowModal] = useState(false);
  const [formData, setFormData] = useState<ProfileFormData>({
    username: "",
    email: "",
    new_password: "",
    current_password: "",
    first_name: "",
    last_name: "",
  });

  const openEditModal = () => {
    const nameParts = (user?.fullName || "").split(" ");
    setFormData({
      username: user?.username || "",
      email: user?.email || "",
      new_password: "",
      current_password: "",
      first_name: nameParts[0] || "",
      last_name: nameParts.slice(1).join(" ") || "",
    });
    setShowModal(true);
  };

  const handleSubmit = async (e?: React.FormEvent) => {
    e?.preventDefault();

    if (formData.new_password && !formData.current_password) {
      alert.error("Pro změnu hesla zadejte aktuální heslo");
      return;
    }
    if (formData.current_password && !formData.new_password) {
      alert.error("Pro změnu hesla zadejte nové heslo");
      return;
    }

    // Build the payload with the password fields optional so empty ones can be
    // omitted (Zod rejects ""), without resorting to `as any` deletes.
    const dataToSave: Partial<
      Pick<ProfileFormData, "current_password" | "new_password">
    > &
      Omit<ProfileFormData, "current_password" | "new_password"> = {
      username: formData.username,
      email: formData.email,
      first_name: formData.first_name,
      last_name: formData.last_name,
    };
    if (formData.current_password)
      dataToSave.current_password = formData.current_password;
    if (formData.new_password) dataToSave.new_password = formData.new_password;

    try {
      const response = await apiFetch(`${API_BASE}/profile`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(dataToSave),
      });
      const data = await response.json();
      if (data.success) {
        updateUser({
          username: dataToSave.username,
          email: dataToSave.email,
          fullName: `${dataToSave.first_name} ${dataToSave.last_name}`.trim(),
        });
        // Refresh anything keyed on the current user's data so stale views
        // (dashboard widgets, user lists) pick up the edited profile.
        queryClient.invalidateQueries({ queryKey: ["dashboard"] });
        queryClient.invalidateQueries({ queryKey: ["users"] });
        setShowModal(false);
        // The 300ms wait is load-bearing: it lets the modal's close fade finish
        // before the success toast appears, so the toast doesn't flash over the
        // still-fading dialog.
        await new Promise((resolve) => setTimeout(resolve, 300));
        alert.success("Profil byl upraven");
      } else {
        alert.error(data.error || "Nepodařilo se uložit profil");
      }
    } catch (err) {
      console.error("DashProfile: uložení profilu selhalo", err);
      alert.error("Chyba připojení");
    }
  };

  function getTotpStatusText(): string {
    if (totpLoading) {
      return "Načítání...";
    }
    return totpEnabled ? "Aktivní" : "Neaktivní";
  }

  const profileItems: Array<{ label: string; value: string }> = [
    { label: "Uživatel", value: user?.username || "" },
    { label: "E-mail", value: user?.email || "" },
    { label: "Jméno", value: user?.fullName || "" },
    {
      label: "Role",
      value: user?.roleDisplay || String(user?.role || ""),
    },
  ];

  return (
    <>
      <motion.div
        initial={reduce ? false : { opacity: 0, y: 12 }}
        animate={reduce ? undefined : { opacity: 1, y: 0 }}
        transition={{ duration: 0.25, delay: 0.15 }}
      >
        <Card>
          <Box
            sx={{
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              mb: 2,
            }}
          >
            <Typography variant="h6">Váš účet</Typography>
            <Button
              onClick={openEditModal}
              variant="outlined"
              color="inherit"
              size="small"
              startIcon={EditIcon}
            >
              Upravit
            </Button>
          </Box>

          <Box
            sx={{
              display: "grid",
              gridTemplateColumns: { xs: "1fr", sm: "1fr 1fr" },
              gap: 1.5,
            }}
          >
            {profileItems.map((item) => (
              <Box key={item.label}>
                <Typography
                  variant="caption"
                  color="text.secondary"
                  sx={{
                    display: "block",
                    textTransform: "uppercase",
                    letterSpacing: ".05em",
                    fontWeight: 600,
                  }}
                >
                  {item.label}
                </Typography>
                <Typography variant="body2" sx={{ fontWeight: 500 }}>
                  {item.value}
                </Typography>
              </Box>
            ))}
          </Box>

          {/* 2FA Section */}
          <Box sx={{ borderTop: 1, borderColor: "divider", mt: 2, pt: 2 }}>
            <Box
              sx={{
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                gap: 1.5,
              }}
            >
              <Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
                <Box
                  sx={[
                    {
                      width: 36,
                      height: 36,
                      borderRadius: "50%",
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "center",
                      flexShrink: 0,
                    },
                    iconBadgeSx(totpEnabled ? "success" : "default"),
                  ]}
                >
                  <svg
                    width="18"
                    height="18"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                  >
                    <rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
                    <path d="M7 11V7a5 5 0 0 1 10 0v4" />
                  </svg>
                </Box>
                <Box>
                  <Typography variant="body2" sx={{ fontWeight: 500 }}>
                    Dvoufaktorové ověření (2FA)
                  </Typography>
                  <Typography
                    variant="caption"
                    sx={{
                      color: totpEnabled ? "success.main" : "text.secondary",
                    }}
                  >
                    {getTotpStatusText()}
                  </Typography>
                </Box>
              </Box>
              {!totpLoading &&
                (totpEnabled ? (
                  <Button
                    onClick={() => {
                      setDisableCode("");
                      setShow2FADisable(true);
                    }}
                    size="small"
                    sx={{ flexShrink: 0 }}
                  >
                    Deaktivovat
                  </Button>
                ) : (
                  <Button
                    onClick={onStart2FASetup}
                    disabled={totpSubmitting}
                    size="small"
                    sx={{ flexShrink: 0 }}
                  >
                    {totpSubmitting ? "Generuji..." : "Aktivovat"}
                  </Button>
                ))}
            </Box>
          </Box>
        </Card>
      </motion.div>

      {/* Edit Profile Modal */}
      <Modal
        isOpen={showModal}
        onClose={() => setShowModal(false)}
        title="Upravit profil"
        maxWidth="sm"
        onSubmit={handleSubmit}
        submitText="Uložit změny"
      >
        <Box
          sx={{
            display: "grid",
            gridTemplateColumns: { xs: "1fr", sm: "1fr 1fr" },
            gap: 2,
          }}
        >
          <Field label="Jméno">
            <TextField
              value={formData.first_name}
              onChange={(e) =>
                setFormData({ ...formData, first_name: e.target.value })
              }
              required
            />
          </Field>
          <Field label="Příjmení">
            <TextField
              value={formData.last_name}
              onChange={(e) =>
                setFormData({ ...formData, last_name: e.target.value })
              }
              required
            />
          </Field>
        </Box>
        <Field label="Uživatelské jméno">
          <TextField
            value={formData.username}
            onChange={(e) =>
              setFormData({ ...formData, username: e.target.value })
            }
            required
          />
        </Field>
        <Field label="E-mail">
          <TextField
            type="email"
            value={formData.email}
            onChange={(e) =>
              setFormData({ ...formData, email: e.target.value })
            }
            required
          />
        </Field>
        <Field label="Aktuální heslo">
          <TextField
            type="password"
            value={formData.current_password}
            onChange={(e) =>
              setFormData({ ...formData, current_password: e.target.value })
            }
            placeholder="Pro změnu hesla, zadejte aktuální heslo"
          />
        </Field>
        <Field label="Nové heslo">
          <TextField
            type="password"
            value={formData.new_password}
            onChange={(e) =>
              setFormData({ ...formData, new_password: e.target.value })
            }
            placeholder="Pro změnu hesla, zadejte nové heslo"
          />
        </Field>
      </Modal>

      {/* 2FA Setup Dialog — bespoke, multi-step: setup → backup codes.
          On the backup-codes step the footer + close are hidden and
          backdrop/ESC are locked; the single deliberate exit lives in the body
          and also clears the codes (so unsaved codes can't be silently lost). */}
      <Dialog
        open={show2FASetup}
        onClose={
          backupCodes
            ? undefined
            : () => {
                setShow2FASetup(false);
                setTotpCode("");
              }
        }
        fullWidth
        maxWidth="sm"
        disableScrollLock
        slotProps={{ paper: { sx: { borderRadius: 3 } } }}
      >
        <DialogTitle>
          {backupCodes ? "Záložní kódy" : "Nastavení 2FA"}
        </DialogTitle>
        <DialogContent>
          {backupCodes ? (
            <Box>
              <Box
                sx={{
                  display: "flex",
                  alignItems: "flex-start",
                  gap: 1,
                  p: 1.5,
                  mb: 2,
                  borderRadius: 2,
                  bgcolor:
                    "rgba(var(--mui-palette-warning-mainChannel) / 0.12)",
                  color: "warning.main",
                  fontSize: "0.875rem",
                }}
              >
                <Box sx={{ flexShrink: 0, mt: "2px" }}>
                  <svg
                    width="16"
                    height="16"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                  >
                    <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
                    <line x1="12" y1="9" x2="12" y2="13" />
                    <line x1="12" y1="17" x2="12.01" y2="17" />
                  </svg>
                </Box>
                <span>
                  Uložte si tyto kódy na bezpečné místo. Každý kód lze použít
                  pouze jednou. Po zavření tohoto okna je již neuvidíte.
                </span>
              </Box>
              <Box
                sx={{
                  display: "grid",
                  gridTemplateColumns: "repeat(2, 1fr)",
                  gap: 1,
                  p: 2,
                  bgcolor: "action.hover",
                  borderRadius: 2,
                  fontFamily: "'DM Mono', Menlo, monospace",
                  fontSize: "1rem",
                }}
              >
                {backupCodes.map((code) => (
                  <Box
                    key={code}
                    sx={{
                      px: 1,
                      py: 0.5,
                      textAlign: "center",
                      color: "text.primary",
                    }}
                  >
                    {code}
                  </Box>
                ))}
              </Box>
              <Box sx={{ mt: 1.5 }}>
                <Button
                  onClick={async () => {
                    const ok = await copyToClipboard(backupCodes.join("\n"));
                    if (ok) alert.success("Kódy zkopírovány");
                    else alert.error("Kopírování selhalo – zkopírujte ručně");
                  }}
                  variant="outlined"
                  color="inherit"
                  size="small"
                  startIcon={CopyIcon}
                >
                  Kopírovat kódy
                </Button>
              </Box>
            </Box>
          ) : (
            <Box>
              <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
                Naskenujte QR kód v autentizační aplikaci (Google Authenticator,
                Authy, Microsoft Authenticator apod.)
              </Typography>
              {totpQrUri && totpQrDataUrl && (
                <Box sx={{ textAlign: "center", mb: 2 }}>
                  <Box
                    component="img"
                    src={totpQrDataUrl}
                    alt="TOTP QR Code"
                    sx={{
                      width: 200,
                      height: 200,
                      borderRadius: 2,
                      border: 1,
                      borderColor: "divider",
                      // The QR must stay scannable in dark mode — keep it on a
                      // white tile instead of inheriting the dark paper bg.
                      bgcolor: "common.white",
                    }}
                  />
                </Box>
              )}
              {totpQrUri && totpQrFailed && (
                <Typography
                  variant="body2"
                  color="warning.main"
                  sx={{ mb: 2, textAlign: "center" }}
                >
                  QR kód se nepodařilo vygenerovat. Zadejte prosím klíč do
                  aplikace ručně.
                </Typography>
              )}
              {totpSecret && (
                <Box sx={{ mb: 2 }}>
                  <Typography
                    component="label"
                    variant="caption"
                    color="text.secondary"
                    sx={{ display: "block", mb: 0.5 }}
                  >
                    Nebo zadejte klíč ručně:
                  </Typography>
                  <Box
                    sx={{
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "space-between",
                      gap: 1,
                      px: 1.5,
                      py: 1,
                      bgcolor: "action.hover",
                      borderRadius: 1.5,
                      fontFamily: "'DM Mono', Menlo, monospace",
                      fontSize: "0.875rem",
                      wordBreak: "break-all",
                      color: "text.primary",
                    }}
                  >
                    <span>{totpSecret}</span>
                    <IconButton
                      onClick={async () => {
                        const ok = await copyToClipboard(totpSecret);
                        if (ok) alert.success("Klíč zkopírován");
                        else
                          alert.error("Kopírování selhalo – zkopírujte ručně");
                      }}
                      size="small"
                      title="Kopírovat"
                      aria-label="Kopírovat"
                      sx={{ flexShrink: 0 }}
                    >
                      {CopyIcon}
                    </IconButton>
                  </Box>
                </Box>
              )}
              <Field label="Ověřovací kód z aplikace">
                <TextField
                  inputRef={totpSetupRef}
                  inputMode="numeric"
                  value={totpCode}
                  onChange={(e) =>
                    setTotpCode(e.target.value.replace(/\D/g, ""))
                  }
                  placeholder="000000"
                  slotProps={{ htmlInput: { maxLength: 6, pattern: "[0-9]*" } }}
                  sx={{
                    "& input": {
                      textAlign: "center",
                      fontSize: "1.25rem",
                      letterSpacing: "0.4rem",
                      fontFamily: "'DM Mono', Menlo, monospace",
                    },
                  }}
                  onKeyDown={(e) => {
                    if (e.key === "Enter" && totpCode.length === 6) {
                      onConfirm2FA();
                    }
                  }}
                />
              </Field>
            </Box>
          )}
        </DialogContent>
        {/* Footer is hidden on the backup-codes step; the single deliberate exit
            lives in the body actions there. */}
        <DialogActions sx={{ px: 3, pb: 2 }}>
          {backupCodes ? (
            <Button
              onClick={() => {
                setShow2FASetup(false);
                setBackupCodes(null);
              }}
            >
              Rozumím, uložil jsem si kódy
            </Button>
          ) : (
            <>
              <Button
                onClick={() => {
                  setShow2FASetup(false);
                  setTotpCode("");
                }}
                variant="text"
                color="inherit"
                disabled={totpSubmitting}
              >
                Zrušit
              </Button>
              <Button
                onClick={onConfirm2FA}
                disabled={totpSubmitting || totpCode.length !== 6}
              >
                {totpSubmitting ? "Ukládám…" : "Aktivovat 2FA"}
              </Button>
            </>
          )}
        </DialogActions>
      </Dialog>

      {/* 2FA Disable Modal */}
      <Modal
        isOpen={show2FADisable}
        onClose={() => setShow2FADisable(false)}
        title="Deaktivovat 2FA"
        maxWidth="sm"
        loading={totpSubmitting}
        onSubmit={onDisable2FA}
        submitDisabled={disableCode.length !== 6}
        submitText="Deaktivovat 2FA"
        cancelText="Zrušit"
      >
        <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
          Pro deaktivaci dvoufaktorového ověření zadejte aktuální kód z
          autentizační aplikace.
        </Typography>
        <Field label="Ověřovací kód">
          <TextField
            inputMode="numeric"
            value={disableCode}
            onChange={(e) => setDisableCode(e.target.value.replace(/\D/g, ""))}
            placeholder="000000"
            autoFocus
            slotProps={{ htmlInput: { maxLength: 6, pattern: "[0-9]*" } }}
            sx={{
              "& input": {
                textAlign: "center",
                fontSize: "1.25rem",
                letterSpacing: "0.4rem",
                fontFamily: "'DM Mono', Menlo, monospace",
              },
            }}
            onKeyDown={(e) => {
              if (e.key === "Enter" && disableCode.length === 6) {
                onDisable2FA();
              }
            }}
          />
        </Field>
      </Modal>
    </>
  );
}
