import express from "express";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { v4 as uuidv4 } from "uuid";
import {
  generateRegistrationOptions,
  verifyRegistrationResponse,
  generateAuthenticationOptions,
  verifyAuthenticationResponse,
} from "@simplewebauthn/server";
import {
  validate,
  loginValidation,
  registerValidation,
} from "../middleware/validate.js";

const router = express.Router();

// In-memory store (replace with database in production)
const users = new Map();
const webAuthnCredentials = new Map();
const sessions = new Map();

// Helper to generate JWT
const generateToken = (user) => {
  return jwt.sign(
    { id: user.id, email: user.email, role: user.role, name: user.name },
    process.env.JWT_SECRET,
    { expiresIn: process.env.JWT_EXPIRES_IN || "7d" },
  );
};

// Register
router.post(
  "/register",
  validate(registerValidation),
  async (req, res, next) => {
    try {
      const { name, email, password } = req.body;

      // Check if user exists
      const existingUser = Array.from(users.values()).find(
        (u) => u.email === email,
      );
      if (existingUser) {
        return res.status(400).json({ error: "Email already registered" });
      }

      // Hash password
      const hashedPassword = await bcrypt.hash(password, 12);

      // Create user
      const user = {
        id: uuidv4(),
        name,
        email,
        password: hashedPassword,
        role: users.size === 0 ? "admin" : "volunteer", // First user is admin
        createdAt: new Date().toISOString(),
      };

      users.set(user.id, user);

      // Generate token
      const token = generateToken(user);

      res.status(201).json({
        message: "User registered successfully",
        token,
        user: {
          id: user.id,
          name: user.name,
          email: user.email,
          role: user.role,
        },
      });
    } catch (error) {
      next(error);
    }
  },
);

// Login
router.post("/login", validate(loginValidation), async (req, res, next) => {
  try {
    const { email, password } = req.body;

    // Find user
    const user = Array.from(users.values()).find((u) => u.email === email);
    if (!user) {
      return res.status(401).json({ error: "Invalid credentials" });
    }

    // Check password
    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      return res.status(401).json({ error: "Invalid credentials" });
    }

    // Generate token
    const token = generateToken(user);

    // Create session
    const sessionId = uuidv4();
    sessions.set(sessionId, {
      userId: user.id,
      createdAt: new Date().toISOString(),
      lastActive: new Date().toISOString(),
    });

    res.json({
      message: "Login successful",
      token,
      user: {
        id: user.id,
        name: user.name,
        email: user.email,
        role: user.role,
      },
    });
  } catch (error) {
    next(error);
  }
});

// Get current user
router.get("/me", (req, res) => {
  // This route should be protected - req.user comes from auth middleware
  if (!req.user) {
    return res.status(401).json({ error: "Not authenticated" });
  }

  const user = users.get(req.user.id);
  if (!user) {
    return res.status(404).json({ error: "User not found" });
  }

  res.json({
    user: { id: user.id, name: user.name, email: user.email, role: user.role },
  });
});

// Logout
router.post("/logout", (req, res) => {
  // Invalidate session on client side
  res.json({ message: "Logged out successfully" });
});

// Google OAuth
router.post("/google", async (req, res, next) => {
  try {
    const { token } = req.body;

    // Verify Google token (simplified - use passport-google-oauth20 in production)
    // For now, return mock response
    res.json({
      message: "Google OAuth not yet configured",
      token: null,
      user: null,
    });
  } catch (error) {
    next(error);
  }
});

// WebAuthn Registration Options
router.post("/webauthn/register-options", async (req, res, next) => {
  try {
    if (!req.user) {
      return res.status(401).json({ error: "Authentication required" });
    }

    const user = users.get(req.user.id);
    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }

    const options = await generateRegistrationOptions({
      rpName: process.env.RP_NAME || "Worship Platform",
      rpID: process.env.RP_ID || "localhost",
      userID: user.id,
      userName: user.email,
      userDisplayName: user.name,
      attestationType: "none",
      authenticatorSelection: {
        residentKey: "preferred",
        userVerification: "preferred",
      },
    });

    // Store challenge for verification
    sessions.set(`webauthn-${user.id}`, {
      challenge: options.challenge,
      createdAt: new Date().toISOString(),
    });

    res.json(options);
  } catch (error) {
    next(error);
  }
});

// WebAuthn Registration Verification
router.post("/webauthn/register", async (req, res, next) => {
  try {
    if (!req.user) {
      return res.status(401).json({ error: "Authentication required" });
    }

    const session = sessions.get(`webauthn-${req.user.id}`);
    if (!session) {
      return res.status(400).json({ error: "Registration session expired" });
    }

    const verification = await verifyRegistrationResponse({
      response: req.body,
      expectedChallenge: session.challenge,
      expectedOrigin: process.env.RP_ORIGIN || "http://localhost:5100",
      expectedRPID: process.env.RP_ID || "localhost",
    });

    if (!verification.verified) {
      return res
        .status(400)
        .json({ error: "Registration verification failed" });
    }

    // Store credential
    const { registrationInfo } = verification;
    webAuthnCredentials.set(req.user.id, {
      credentialID: registrationInfo.credentialID,
      credentialPublicKey: registrationInfo.credentialPublicKey,
      counter: registrationInfo.counter,
      transports: req.body.response.transports,
    });

    // Clean up session
    sessions.delete(`webauthn-${req.user.id}`);

    res.json({ message: "Biometric registration successful" });
  } catch (error) {
    next(error);
  }
});

// WebAuthn Authentication Options
router.post("/webauthn/authenticate-options", async (req, res, next) => {
  try {
    const { email } = req.body;

    // Find user by email or use session
    const user = email
      ? Array.from(users.values()).find((u) => u.email === email)
      : null;

    const options = await generateAuthenticationOptions({
      rpID: process.env.RP_ID || "localhost",
      userVerification: "preferred",
      allowCredentials:
        user && webAuthnCredentials.has(user.id)
          ? [
              {
                id: webAuthnCredentials.get(user.id).credentialID,
                type: "public-key",
                transports: webAuthnCredentials.get(user.id).transports,
              },
            ]
          : [],
    });

    // Store challenge
    const sessionKey = user ? `webauthn-auth-${user.id}` : `webauthn-auth-temp`;
    sessions.set(sessionKey, {
      challenge: options.challenge,
      userId: user?.id,
      createdAt: new Date().toISOString(),
    });

    res.json(options);
  } catch (error) {
    next(error);
  }
});

// WebAuthn Authentication Verification
router.post("/webauthn/authenticate", async (req, res, next) => {
  try {
    // Find credential and user
    let userId = null;
    let credential = null;

    for (const [id, cred] of webAuthnCredentials.entries()) {
      if (
        Buffer.compare(
          cred.credentialID,
          Buffer.from(req.body.id, "base64url"),
        ) === 0
      ) {
        userId = id;
        credential = cred;
        break;
      }
    }

    if (!userId || !credential) {
      return res.status(400).json({ error: "Credential not found" });
    }

    const session = sessions.get(`webauthn-auth-${userId}`);
    if (!session) {
      return res.status(400).json({ error: "Authentication session expired" });
    }

    const verification = await verifyAuthenticationResponse({
      response: req.body,
      expectedChallenge: session.challenge,
      expectedOrigin: process.env.RP_ORIGIN || "http://localhost:5100",
      expectedRPID: process.env.RP_ID || "localhost",
      authenticator: credential,
    });

    if (!verification.verified) {
      return res
        .status(400)
        .json({ error: "Authentication verification failed" });
    }

    // Update counter
    credential.counter = verification.authenticationInfo.newCounter;

    const user = users.get(userId);
    const token = generateToken(user);

    // Clean up session
    sessions.delete(`webauthn-auth-${userId}`);

    res.json({
      message: "Biometric authentication successful",
      token,
      user: {
        id: user.id,
        name: user.name,
        email: user.email,
        role: user.role,
      },
    });
  } catch (error) {
    next(error);
  }
});

// Switch profile
router.post("/switch-profile", (req, res, next) => {
  try {
    const { profileId } = req.body;

    // In a real app, this would switch to a different profile/user context
    const user = users.get(profileId);
    if (!user) {
      return res.status(404).json({ error: "Profile not found" });
    }

    const token = generateToken(user);

    res.json({
      message: "Profile switched successfully",
      token,
      user: {
        id: user.id,
        name: user.name,
        email: user.email,
        role: user.role,
      },
    });
  } catch (error) {
    next(error);
  }
});

export default router;
