import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["nickname", "submitButton", "status", "error"];
  static values = {
    challengeUrl: String,
    createUrl: String,
    checkUrl: String
  };

  connect() {
    // Check if WebAuthn is supported
    if (!this.isWebAuthnSupported()) {
      console.warn("WebAuthn is not supported in this browser");
      return;
    }
  }

  // Check if browser supports WebAuthn
  isWebAuthnSupported() {
    return (
      window.PublicKeyCredential !== undefined &&
      typeof window.PublicKeyCredential === "function"
    );
  }

  // Check if user has passkeys (for login page)
  async checkWebAuthnSupport(event) {
    const email = event.target.value.trim();

    if (!email || !this.isValidEmail(email)) {
      return;
    }

    try {
      const response = await fetch(`${this.checkUrlValue}?email=${encodeURIComponent(email)}`);
      const data = await response.json();

      console.debug("WebAuthn check response:", data);

      if (data.has_webauthn) {
        console.debug("Dispatching webauthn-available event");
        // Trigger custom event for login form to show passkey option
        this.dispatch("webauthn-available", {
          detail: {
            hasWebauthn: data.has_webauthn,
            requiresWebauthn: data.requires_webauthn,
            preferredMethod: data.preferred_method
          }
        });

        // Don't auto-trigger navigator.credentials.get() — Safari's WebAuthn
        // dialog can become undismissable when invoked without a user gesture.
        // Always let the user click "Continue with Passkey" instead.
      } else {
        console.debug("No WebAuthn credentials found for this email");
      }
    } catch (error) {
      console.error("Error checking WebAuthn support:", error);
    }
  }

  // Start registration ceremony
  async register(event) {
    event.preventDefault();

    if (!this.isWebAuthnSupported()) {
      this.showError("WebAuthn is not supported in your browser");
      return;
    }

    const nickname = this.nicknameTarget.value.trim();
    if (!nickname) {
      this.showError("Please enter a nickname for this passkey");
      return;
    }

    this.setLoading(true);
    this.clearMessages();

    try {
      // Get registration challenge from server
      const challengeResponse = await fetch(this.challengeUrlValue, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-CSRF-Token": this.getCSRFToken()
        }
      });

      if (!challengeResponse.ok) {
        throw new Error("Failed to get registration challenge");
      }

      const credentialCreationOptions = await challengeResponse.json();

      // Use modern Web Authentication API Level 3 to parse options
      // This automatically handles all base64url encoding/decoding
      const publicKeyOptions = PublicKeyCredential.parseCreationOptionsFromJSON(
        credentialCreationOptions
      );

      // Create credential via WebAuthn API
      const credential = await navigator.credentials.create({
        publicKey: publicKeyOptions
      });

      if (!credential) {
        throw new Error("Failed to create credential");
      }

      // Send credential to server for verification
      // Use toJSON() to properly serialize the credential
      const credentialResponse = await fetch(this.createUrlValue, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-CSRF-Token": this.getCSRFToken()
        },
        body: JSON.stringify({
          credential: credential.toJSON(),
          nickname: nickname
        })
      });

      const result = await credentialResponse.json();

      if (result.success) {
        this.showSuccess(result.message);

        // Clear the form
        this.nicknameTarget.value = "";

        // Dispatch event to refresh the passkey list
        this.dispatch("passkey-registered", {
          detail: {
            nickname: nickname,
            credentialId: result.credential_id
          }
        });

        // Optionally close modal or redirect
        setTimeout(() => {
          if (window.location.pathname === "/webauthn/new") {
            window.location.href = "/profile";
          }
        }, 1500);
      } else {
        this.showError(result.error || "Failed to register passkey");
      }

    } catch (error) {
      console.error("WebAuthn registration error:", error);
      this.showError(this.getErrorMessage(error));
    } finally {
      this.setLoading(false);
    }
  }

  // Start authentication ceremony
  async authenticate(event) {
    if (event) {
      event.preventDefault();
    }

    if (!this.isWebAuthnSupported()) {
      this.showError("WebAuthn is not supported in your browser");
      return;
    }

    this.setLoading(true);
    this.clearMessages();

    try {
      // Get authentication challenge from server
      const response = await fetch("/sessions/webauthn/challenge", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-CSRF-Token": this.getCSRFToken()
        },
        body: JSON.stringify({
          email: this.getUserEmail(),
          remember_me: this.getRememberMe()
        })
      });

      if (!response.ok) {
        throw new Error("Failed to get authentication challenge");
      }

      const credentialRequestOptions = await response.json();

      // Use modern Web Authentication API Level 3 to parse options
      // This automatically handles all base64url encoding/decoding
      const publicKeyOptions = PublicKeyCredential.parseRequestOptionsFromJSON(
        credentialRequestOptions
      );

      // Get credential via WebAuthn API
      const credential = await navigator.credentials.get({
        publicKey: publicKeyOptions
      });

      if (!credential) {
        throw new Error("Failed to get credential");
      }

      // Send assertion to server for verification
      // Use toJSON() to properly serialize the credential
      const authResponse = await fetch("/sessions/webauthn/verify", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-CSRF-Token": this.getCSRFToken()
        },
        body: JSON.stringify({
          credential: credential.toJSON(),
          email: this.getUserEmail()
        })
      });

      const result = await authResponse.json();

      if (result.success) {
        // Redirect to dashboard or intended URL
        window.location.href = result.redirect_to || "/";
      } else {
        this.showError(result.error || "Authentication failed");
      }

    } catch (error) {
      console.error("WebAuthn authentication error:", error);
      this.showError(this.getErrorMessage(error));
    } finally {
      this.setLoading(false);
    }
  }

  // UI helper methods
  setLoading(isLoading) {
    if (this.hasSubmitButtonTarget) {
      this.submitButtonTarget.disabled = isLoading;
      this.submitButtonTarget.textContent = isLoading ? "Registering..." : "Register Passkey";
    }
  }

  showSuccess(message) {
    if (this.hasStatusTarget) {
      this.statusTarget.textContent = message;
      this.statusTarget.className = "mt-2 text-sm text-green-600";
      this.statusTarget.style.display = "block";
    }
  }

  showError(message) {
    if (this.hasErrorTarget) {
      this.errorTarget.textContent = message;
      this.errorTarget.className = "mt-2 text-sm text-red-600";
      this.errorTarget.style.display = "block";
    }
  }

  clearMessages() {
    if (this.hasStatusTarget) {
      this.statusTarget.style.display = "none";
      this.statusTarget.textContent = "";
    }
    if (this.hasErrorTarget) {
      this.errorTarget.style.display = "none";
      this.errorTarget.textContent = "";
    }
  }

  getCSRFToken() {
    const meta = document.querySelector('meta[name="csrf-token"]');
    return meta ? meta.getAttribute("content") : "";
  }

  getUserEmail() {
    // Try multiple ways to get the user email from login form
    let emailInput = document.querySelector('input[type="email"]');
    if (!emailInput) {
      emailInput = document.querySelector('input[name="email"]');
    }
    if (!emailInput) {
      emailInput = document.querySelector('input[name="session[email_address]"]');
    }
    if (!emailInput) {
      emailInput = document.querySelector('input[name="user[email_address]"]');
    }
    // Fallback to hidden webauthn_email field (e.g., on TOTP verification page)
    if (!emailInput) {
      emailInput = document.querySelector('input[name="webauthn_email"]');
    }
    return emailInput ? emailInput.value.trim() : "";
  }

  getRememberMe() {
    const checkbox = document.querySelector('input[name="remember_me"][type="checkbox"]');
    return checkbox ? checkbox.checked : false;
  }

  isValidEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }

  getErrorMessage(error) {
    // Common WebAuthn errors
    if (error.name === "NotAllowedError") {
      return "Authentication was cancelled or timed out. Please try again.";
    }
    if (error.name === "SecurityError") {
      return "Security requirements not met. Make sure you're using HTTPS.";
    }
    if (error.name === "NotSupportedError") {
      return "This device doesn't support the requested authentication method.";
    }
    if (error.name === "InvalidStateError") {
      return "This authenticator has already been registered.";
    }

    // Fallback to a user-friendly message
    return "Passkey authentication failed. A browser extension may be interfering — try using your password instead.";
  }
}
