import { useMemo, useState } from "react";
import { api, setAccessToken } from "../lib/api";

function initialLoginForm() {
  return {
    email: "",
    password: "",
  };
}

function initialTotpForm() {
  return {
    totp_code: "",
  };
}

function base64UrlToUint8Array(value) {
  if (!value || typeof value !== "string") return value;
  const padding = "=".repeat((4 - (value.length % 4)) % 4);
  const base64 = (value + padding).replace(/-/g, "+").replace(/_/g, "/");
  const raw = window.atob(base64);
  const bytes = new Uint8Array(raw.length);
  for (let i = 0; i < raw.length; i += 1) {
    bytes[i] = raw.charCodeAt(i);
  }
  return bytes;
}

function publicKeyOptionsFromServer(options) {
  if (!options) return options;

  const publicKey = { ...options };

  if (publicKey.challenge) {
    publicKey.challenge = base64UrlToUint8Array(publicKey.challenge);
  }

  if (Array.isArray(publicKey.allowCredentials)) {
    publicKey.allowCredentials = publicKey.allowCredentials.map((item) => ({
      ...item,
      id: base64UrlToUint8Array(item.id),
    }));
  }

  if (Array.isArray(publicKey.excludeCredentials)) {
    publicKey.excludeCredentials = publicKey.excludeCredentials.map((item) => ({
      ...item,
      id: base64UrlToUint8Array(item.id),
    }));
  }

  if (publicKey.user?.id) {
    publicKey.user = {
      ...publicKey.user,
      id: base64UrlToUint8Array(publicKey.user.id),
    };
  }

  return publicKey;
}

function uint8ArrayToBase64Url(bytes) {
  if (!bytes) return "";
  const array = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
  let binary = "";
  for (let i = 0; i < array.byteLength; i += 1) {
    binary += String.fromCharCode(array[i]);
  }
  return window
    .btoa(binary)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/g, "");
}

function serializeAssertionCredential(credential) {
  if (!credential) return null;

  return {
    id: credential.id,
    rawId: uint8ArrayToBase64Url(credential.rawId),
    type: credential.type,
    response: {
      authenticatorData: uint8ArrayToBase64Url(credential.response?.authenticatorData),
      clientDataJSON: uint8ArrayToBase64Url(credential.response?.clientDataJSON),
      signature: uint8ArrayToBase64Url(credential.response?.signature),
      userHandle: credential.response?.userHandle
        ? uint8ArrayToBase64Url(credential.response.userHandle)
        : null,
    },
    clientExtensionResults: credential.getClientExtensionResults
      ? credential.getClientExtensionResults()
      : {},
  };
}

export default function LoginPage({ onLogin }) {
  const [loginForm, setLoginForm] = useState(initialLoginForm());
  const [totpForm, setTotpForm] = useState(initialTotpForm());
  const [stage, setStage] = useState("password");
  const [loginToken, setLoginToken] = useState("");
  const [userHint, setUserHint] = useState(null);
  const [availableSecondFactors, setAvailableSecondFactors] = useState({
    totp: false,
    webauthn: false,
  });
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);

  const canUseWebAuthn = useMemo(() => {
    return typeof window !== "undefined" && !!window.PublicKeyCredential && !!navigator.credentials;
  }, []);

  function completeLogin(result) {
    if (!result?.accessToken || !result?.user) {
      throw new Error("Login-Antwort unvollständig");
    }

    setAccessToken(result.accessToken);
    localStorage.setItem("br_user", JSON.stringify(result.user));
    setMessage("");
    setError("");
    onLogin?.(result.user);
  }

  async function handlePasswordLogin(e) {
    e.preventDefault();
    setBusy(true);
    setError("");
    setMessage("");

    try {
      const result = await api.post("/auth/login", {
        email: loginForm.email.trim(),
        password: loginForm.password,
      });

      if (result?.mfaRequired) {
        setLoginToken(result.loginToken || "");
        setUserHint(result.userHint || null);
        setAvailableSecondFactors({
          totp: Boolean(result?.availableSecondFactors?.totp),
          webauthn: Boolean(result?.availableSecondFactors?.webauthn),
        });

        if (result?.availableSecondFactors?.totp) {
          setStage("totp");
          setMessage("Bitte zweiten Faktor mit TOTP bestätigen.");
        } else if (result?.availableSecondFactors?.webauthn) {
          setStage("webauthn");
          setMessage("Bitte Anmeldung mit Sicherheitsschlüssel oder Passkey bestätigen.");
        } else {
          setStage("mfa-choice");
          setMessage("Zweiter Faktor erforderlich.");
        }
        return;
      }

      completeLogin(result);
    } catch (err) {
      setError(err.message || "Login fehlgeschlagen.");
    } finally {
      setBusy(false);
    }
  }

  async function handleTotpLogin(e) {
    e.preventDefault();
    setBusy(true);
    setError("");
    setMessage("");

    try {
      const result = await api.post("/auth/login/totp", {
        login_token: loginToken,
        totp_code: totpForm.totp_code.trim(),
      });

      completeLogin(result);
    } catch (err) {
      setError(err.message || "TOTP-Anmeldung fehlgeschlagen.");
    } finally {
      setBusy(false);
    }
  }

  async function handleWebAuthnLogin() {
    setBusy(true);
    setError("");
    setMessage("");

    try {
      if (!canUseWebAuthn) {
        throw new Error("WebAuthn wird in diesem Browser nicht unterstützt.");
      }

      const options = await api.post("/auth/login/webauthn/options", {
        login_token: loginToken,
      });

      const credential = await navigator.credentials.get({
        publicKey: publicKeyOptionsFromServer(options),
      });

      if (!credential) {
        throw new Error("WebAuthn-Anmeldung wurde abgebrochen.");
      }

      const result = await api.post("/auth/login/webauthn/verify", {
        login_token: loginToken,
        credential: serializeAssertionCredential(credential),
      });

      completeLogin(result);
    } catch (err) {
      setError(err.message || "WebAuthn-Anmeldung fehlgeschlagen.");
    } finally {
      setBusy(false);
    }
  }

  function resetToPasswordStage() {
    setStage("password");
    setLoginToken("");
    setTotpForm(initialTotpForm());
    setAvailableSecondFactors({ totp: false, webauthn: false });
    setUserHint(null);
    setMessage("");
    setError("");
  }

  return (
    <>
      <style>{`
        .login-shell {
          min-height: 100vh;
          display: grid;
          place-items: center;
          padding: 24px;
          background:
            radial-gradient(circle at top left, rgba(37, 99, 235, 0.10), transparent 28%),
            radial-gradient(circle at bottom right, rgba(220, 38, 38, 0.08), transparent 24%),
            linear-gradient(180deg, #f4f7fb 0%, #eef3f8 100%);
        }

        .login-card {
          width: min(540px, 100%);
          background: rgba(255, 255, 255, 0.74);
          backdrop-filter: blur(18px);
          -webkit-backdrop-filter: blur(18px);
          border: 1px solid rgba(15, 23, 42, 0.08);
          border-radius: 24px;
          box-shadow: 0 20px 60px rgba(15, 23, 42, 0.12);
          padding: 24px;
          backdrop-filter: blur(10px);
        }

        .login-header {
          margin-bottom: 18px;
        }

        .login-header h1 {
          margin: 0;
          font-size: 1.8rem;
        }

        .login-header p {
          margin: 8px 0 0;
          color: #64748b;
        }

        .login-meta {
          margin-bottom: 14px;
          padding: 12px 14px;
          border-radius: 14px;
          background: rgba(15, 23, 42, 0.04);
          color: #334155;
        }

        .login-actions {
          display: flex;
          justify-content: flex-end;
          gap: 10px;
          margin-top: 8px;
          flex-wrap: wrap;
        }

        .login-choice-actions {
          display: flex;
          gap: 10px;
          flex-wrap: wrap;
          margin-top: 12px;
        }
      `}</style>

      <div className="login-shell">
        <div className="login-card">
          <div className="login-header">
            <h1>BR-Office</h1>
            <p>
              {stage === "password"
                ? "Bitte anmelden."
                : "Bitte zweiten Faktor bestätigen."}
            </p>
          </div>

          {userHint ? (
            <div className="login-meta">
              <strong>{userHint.full_name || userHint.email}</strong>
              <div>{userHint.email}</div>
              <div>{userHint.role}</div>
            </div>
          ) : null}

          {error ? <div className="alert error">{error}</div> : null}
          {message ? <div className="alert success">{message}</div> : null}

          {stage === "password" ? (
            <form className="form-grid" onSubmit={handlePasswordLogin}>
              <label>
                <span>E-Mail</span>
                <input
                  className="input"
                  type="email"
                  autoComplete="username"
                  value={loginForm.email}
                  onChange={(e) =>
                    setLoginForm((prev) => ({ ...prev, email: e.target.value }))
                  }
                />
              </label>

              <label>
                <span>Passwort</span>
                <input
                  className="input"
                  type="password"
                  autoComplete="current-password"
                  value={loginForm.password}
                  onChange={(e) =>
                    setLoginForm((prev) => ({ ...prev, password: e.target.value }))
                  }
                />
              </label>

              <div className="login-actions">
                <button className="btn" type="submit" disabled={busy}>
                  {busy ? "Anmelden..." : "Anmelden"}
                </button>
              </div>
            </form>
          ) : null}

          {stage === "mfa-choice" ? (
            <div>
              <p className="field-hint">
                Es ist ein zweiter Faktor erforderlich. Bitte eine Methode auswählen.
              </p>

              <div className="login-choice-actions">
                {availableSecondFactors.totp ? (
                  <button
                    className="btn"
                    type="button"
                    onClick={() => {
                      setStage("totp");
                      setError("");
                      setMessage("");
                    }}
                    disabled={busy}
                  >
                    TOTP verwenden
                  </button>
                ) : null}

                {availableSecondFactors.webauthn ? (
                  <button
                    className="btn secondary"
                    type="button"
                    onClick={() => {
                      setStage("webauthn");
                      setError("");
                      setMessage("");
                    }}
                    disabled={busy}
                  >
                    WebAuthn verwenden
                  </button>
                ) : null}

                <button
                  className="btn secondary"
                  type="button"
                  onClick={resetToPasswordStage}
                  disabled={busy}
                >
                  Zurück
                </button>
              </div>
            </div>
          ) : null}

          {stage === "totp" ? (
            <form className="form-grid" onSubmit={handleTotpLogin}>
              <label>
                <span>TOTP-Code</span>
                <input
                  className="input"
                  inputMode="numeric"
                  autoComplete="one-time-code"
                  placeholder="123456"
                  value={totpForm.totp_code}
                  onChange={(e) =>
                    setTotpForm((prev) => ({ ...prev, totp_code: e.target.value }))
                  }
                />
              </label>

              <div className="login-actions">
                {availableSecondFactors.webauthn ? (
                  <button
                    className="btn secondary"
                    type="button"
                    onClick={() => {
                      setStage("webauthn");
                      setError("");
                      setMessage("");
                    }}
                    disabled={busy}
                  >
                    WebAuthn stattdessen
                  </button>
                ) : null}

                <button
                  className="btn secondary"
                  type="button"
                  onClick={resetToPasswordStage}
                  disabled={busy}
                >
                  Abbrechen
                </button>

                <button className="btn" type="submit" disabled={busy}>
                  {busy ? "Prüfen..." : "Bestätigen"}
                </button>
              </div>
            </form>
          ) : null}

          {stage === "webauthn" ? (
            <div>
              <p className="field-hint">
                Mit Sicherheitsschlüssel, Windows Hello, Touch ID oder Passkey anmelden.
              </p>

              <div className="login-actions">
                {availableSecondFactors.totp ? (
                  <button
                    className="btn secondary"
                    type="button"
                    onClick={() => {
                      setStage("totp");
                      setError("");
                      setMessage("");
                    }}
                    disabled={busy}
                  >
                    TOTP stattdessen
                  </button>
                ) : null}

                <button
                  className="btn secondary"
                  type="button"
                  onClick={resetToPasswordStage}
                  disabled={busy}
                >
                  Abbrechen
                </button>

                <button className="btn" type="button" onClick={handleWebAuthnLogin} disabled={busy}>
                  {busy ? "Anmeldung läuft..." : "WebAuthn starten"}
                </button>
              </div>
            </div>
          ) : null}
        </div>
      </div>
    </>
  );
}
