/**
 * Biometric Authentication - Store credentials and unlock with fingerprint
 * This is NOT WebAuthn passkeys - it's using biometric to unlock stored username
 */

const API_BASE = window.location.origin;

/**
 * Check if biometric authentication is available on this device
 */
export async function isBiometricAvailable() {
  // Check if we're on HTTPS or localhost
  const isSecureContext = window.isSecureContext;
  const isLocalhost =
    window.location.hostname === "localhost" ||
    window.location.hostname === "127.0.0.1";

  if (!isSecureContext && !isLocalhost) {
    return {
      available: false,
      reason:
        "HTTPS required for biometric authentication. Please access via https://",
    };
  }

  if (!window.PublicKeyCredential) {
    return {
      available: false,
      reason: "Biometric authentication not supported by this browser",
    };
  }

  try {
    const available =
      await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
    if (!available) {
      return {
        available: false,
        reason: "No biometric authenticator found on this device",
      };
    }

    return { available: true, type: "biometric" };
  } catch (error) {
    console.error("Error checking biometric availability:", error);
    return { available: false, reason: error.message };
  }
}

/**
 * Get device information for identification
 */
function getDeviceInfo() {
  const ua = navigator.userAgent;
  let deviceName = "Unknown Device";

  if (/iPhone/.test(ua)) deviceName = "iPhone";
  else if (/iPad/.test(ua)) deviceName = "iPad";
  else if (/Android/.test(ua)) deviceName = "Android Device";
  else if (/Windows/.test(ua)) deviceName = "Windows PC";
  else if (/Mac/.test(ua)) deviceName = "Mac";
  else if (/Linux/.test(ua)) deviceName = "Linux PC";

  return {
    name: deviceName,
    info: ua,
  };
}

/**
 * Generate a simple device fingerprint for this browser/device
 * Robust for mobile devices with proper fallbacks
 */
function generateDeviceFingerprint() {
  try {
    // Collect device characteristics with fallbacks for mobile
    const characteristics = [
      navigator.userAgent || "unknown-ua",
      navigator.language || navigator.userLanguage || "unknown-lang",
      (screen.width || 0) + "x" + (screen.height || 0),
      screen.colorDepth || "unknown-color",
      new Date().getTimezoneOffset() || 0,
      !!window.sessionStorage,
      !!window.localStorage,
      navigator.platform || "unknown-platform",
      navigator.hardwareConcurrency || "unknown-cpu",
      screen.pixelDepth || "unknown-depth",
    ].join("|");

    console.log(
      "[Biometric] Generating fingerprint from characteristics:",
      characteristics
    );

    // Simple hash function
    let hash = 0;
    for (let i = 0; i < characteristics.length; i++) {
      const char = characteristics.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash = hash & hash; // Convert to 32-bit integer
    }

    const fingerprint = Math.abs(hash).toString(36);
    console.log("[Biometric] Generated fingerprint:", fingerprint);

    if (!fingerprint || fingerprint === "0") {
      throw new Error("Failed to generate valid fingerprint");
    }

    return fingerprint;
  } catch (error) {
    console.error("[Biometric] Error generating fingerprint:", error);
    // Fallback: Use timestamp + random number for unique identifier
    const fallbackFingerprint =
      Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
    console.log("[Biometric] Using fallback fingerprint:", fallbackFingerprint);
    return fallbackFingerprint;
  }
}

/**
 * Register biometric for a user - links their username to this device's biometric
 */
export async function registerBiometric(username) {
  try {
    console.log("[Biometric] Registering biometric for:", username);

    // Check availability first
    const availability = await isBiometricAvailable();
    if (!availability.available) {
      throw new Error(availability.reason);
    }

    // Get device info
    const deviceInfo = getDeviceInfo();
    const deviceFingerprint = generateDeviceFingerprint();

    console.log(
      "[Biometric] Device:",
      deviceInfo.name,
      "Fingerprint:",
      deviceFingerprint
    );

    // Validate fingerprint was generated
    if (!deviceFingerprint) {
      throw new Error(
        "Failed to generate device fingerprint. Please try again."
      );
    }

    // Test biometric authentication
    console.log("[Biometric] Testing device biometric...");

    // Create a simple credential to verify biometric works
    const challenge = new Uint8Array(32);
    crypto.getRandomValues(challenge);

    const publicKeyOptions = {
      challenge: challenge,
      rp: {
        name: "HOP Worship",
        id:
          window.location.hostname === "localhost"
            ? "localhost"
            : window.location.hostname,
      },
      user: {
        id: new TextEncoder().encode(username),
        name: username,
        displayName: username,
      },
      pubKeyCredParams: [
        { type: "public-key", alg: -7 }, // ES256
        { type: "public-key", alg: -257 }, // RS256
      ],
      authenticatorSelection: {
        authenticatorAttachment: "platform",
        userVerification: "required", // This triggers fingerprint/face
        requireResidentKey: false,
      },
      timeout: 60000,
      attestation: "none",
    };

    console.log("[Biometric] Prompting for fingerprint/face...");
    const credential = await navigator.credentials.create({
      publicKey: publicKeyOptions,
    });

    if (!credential) {
      throw new Error("Biometric verification failed");
    }

    console.log("[Biometric] Biometric verified! Saving to backend...");

    // Register with backend - just store device fingerprint linked to username
    const registerPayload = {
      username: username,
      deviceName: deviceInfo.name,
      deviceFingerprint: deviceFingerprint,
      deviceInfo: deviceInfo.info,
    };

    console.log("[Biometric] Sending registration to backend:", {
      username,
      deviceName: deviceInfo.name,
      deviceFingerprint,
    });

    const response = await fetch(`${API_BASE}/api/biometric/register`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "include",
      body: JSON.stringify(registerPayload),
    });

    console.log("[Biometric] Backend response status:", response.status);

    const result = await response.json();
    console.log("[Biometric] Backend response:", result);

    if (!response.ok || !result.success) {
      throw new Error(result.error || result.message || "Registration failed");
    }

    // Store username locally so we can auto-fill on next visit
    localStorage.setItem("biometric_username", username);
    localStorage.setItem("biometric_device", deviceFingerprint);

    console.log("[Biometric] Registration successful!");
    return { success: true };
  } catch (error) {
    console.error("[Biometric] Registration error:", error);

    let errorMessage = error.message;
    if (error.name === "NotAllowedError") {
      errorMessage =
        "Biometric was cancelled. Please try again and allow access.";
    } else if (error.name === "SecurityError") {
      errorMessage = "Security error: This feature requires HTTPS.";
    }

    return { success: false, error: errorMessage };
  }
}

/**
 * Authenticate using biometric - unlocks stored credentials
 */
export async function authenticateBiometric() {
  try {
    console.log("[Biometric] Starting biometric authentication...");

    // Check availability
    const availability = await isBiometricAvailable();
    if (!availability.available) {
      throw new Error(availability.reason);
    }

    // Get stored username (optional - backend can lookup by device fingerprint)
    const savedUsername = localStorage.getItem("biometric_username");
    const deviceFingerprint = generateDeviceFingerprint();

    console.log(
      "[Biometric] Saved username:",
      savedUsername || "none (will lookup by device)"
    );
    console.log("[Biometric] Device fingerprint:", deviceFingerprint);

    // Prompt for biometric verification
    console.log("[Biometric] Prompting for fingerprint/face authentication...");

    // Use a simple WebAuthn prompt to trigger device biometric
    // This creates a temporary credential just to verify biometric
    const challenge = new Uint8Array(32);
    crypto.getRandomValues(challenge);

    try {
      // Try to create a simple credential to trigger biometric prompt
      const publicKeyOptions = {
        challenge: challenge,
        rp: {
          name: "HOP Worship",
          id:
            window.location.hostname === "localhost"
              ? "localhost"
              : window.location.hostname,
        },
        user: {
          id: new Uint8Array(16), // Random ID
          name: savedUsername || "user",
          displayName: savedUsername || "User",
        },
        pubKeyCredParams: [
          { type: "public-key", alg: -7 }, // ES256
          { type: "public-key", alg: -257 }, // RS256
        ],
        authenticatorSelection: {
          authenticatorAttachment: "platform",
          userVerification: "required", // This triggers fingerprint/face
        },
        timeout: 60000,
        attestation: "none",
      };

      await navigator.credentials.create({
        publicKey: publicKeyOptions,
      });

      console.log("[Biometric] Biometric verified!");
    } catch (bioError) {
      // If user cancelled or biometric failed
      if (bioError.name === "NotAllowedError") {
        throw new Error("Biometric authentication was cancelled");
      }
      console.log(
        "[Biometric] Biometric prompt failed, but continuing:",
        bioError.message
      );
      // Continue anyway - backend will verify based on device fingerprint
    }

    console.log("[Biometric] Sending authentication request to backend...");

    // Send to backend for verification (username optional - backend can lookup by device)
    const authPayload = {
      deviceFingerprint: deviceFingerprint,
    };
    if (savedUsername) {
      authPayload.username = savedUsername;
    }

    console.log("[Biometric] Sending auth request:", authPayload);

    const response = await fetch(`${API_BASE}/api/biometric/authenticate`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "include",
      body: JSON.stringify(authPayload),
    });

    console.log("[Biometric] Backend response status:", response.status);
    const result = await response.json();
    console.log("[Biometric] Backend response:", result);

    if (!result.success) {
      throw new Error(result.error || "Authentication failed");
    }

    console.log("[Biometric] Login successful for user:", result.username);

    return {
      success: true,
      username: result.username,
      role: result.role,
      permissions: result.permissions,
    };
  } catch (error) {
    console.error("[Biometric] Authentication error:", error);

    let errorMessage = error.message;
    if (error.name === "NotAllowedError") {
      errorMessage = "Biometric was cancelled. Please try again.";
    } else if (error.name === "NotFoundError") {
      errorMessage =
        "No biometric setup found. Please use password login and setup biometric.";
    }

    return { success: false, error: errorMessage };
  }
}

/**
 * Remove biometric authentication for a user
 */
export async function removeBiometric(username) {
  try {
    console.log("[Biometric] Removing biometric for:", username);

    const response = await fetch(
      `${API_BASE}/api/biometric/remove/${username}`,
      {
        method: "DELETE",
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    const result = await response.json();
    console.log("[Biometric] Remove response:", result);

    if (!response.ok) {
      throw new Error(result.error || "Failed to remove biometric");
    }

    if (result.success) {
      console.log(
        "[Biometric] Successfully removed",
        result.deleted_count,
        "credential(s)"
      );
      return {
        success: true,
        message: `Removed ${result.deleted_count} biometric credential(s)`,
      };
    } else {
      throw new Error(result.error || "Failed to remove biometric");
    }
  } catch (error) {
    console.error("[Biometric] Error removing biometric:", error);
    return { success: false, error: error.message };
  }
}
