import { Router, Request, Response } from "express";
import crypto from "crypto";
import { getDb } from "../../src/db";
import {
  hashPassword,
  comparePassword,
  generateAccessToken,
  generateRefreshToken,
  verifyRefreshToken,
  verifyAccessToken
} from "../../src/auth";

export const authRouter = Router();

// Endpoint: REGISTER
authRouter.post("/register", async (req: Request, res: Response) => {
  try {
    const { username, email, password } = req.body;

    // Basic Validation
    if (!username || !email || !password) {
      return res.status(400).json({ error: "username, email, and password are required." });
    }

    if (username.length < 3) {
      return res.status(400).json({ error: "Username must be at least 3 characters long." });
    }

    if (password.length < 6) {
      return res.status(400).json({ error: "Password must be at least 6 characters long." });
    }

    const db = await getDb();

    // Check if username or email already exists
    const existingUser = await db.get(
      "SELECT id FROM users WHERE username = ? OR email = ?",
      [username.toLowerCase(), email.toLowerCase()]
    );

    if (existingUser) {
      return res.status(409).json({ error: "Username or Email already registered." });
    }

    // Hash password & generate IDs
    const hashedPassword = await hashPassword(password);
    const userId = crypto.randomUUID();
    const profileId = crypto.randomUUID();

    // Perform inserts in a simple transaction/sequence
    await db.run("BEGIN TRANSACTION;");
    try {
      await db.run(
        "INSERT INTO users (id, username, email, password_hash) VALUES (?, ?, ?, ?)",
        [userId, username, email.toLowerCase(), hashedPassword]
      );

      await db.run(
        "INSERT INTO player_profiles (id, user_id, resonance_level, gold, experience, metadata) VALUES (?, ?, 5, 0, 0, ?)",
        [profileId, userId, JSON.stringify({ items: [], unlockedCards: [] })]
      );

      await db.run("COMMIT;");
    } catch (err) {
      await db.run("ROLLBACK;");
      throw err;
    }

    return res.status(201).json({
      message: "User registered successfully.",
      userId
    });

  } catch (error: any) {
    console.error("Registration error:", error);
    return res.status(500).json({ error: "Internal server error during registration." });
  }
});

// Endpoint: LOGIN
authRouter.post("/login", async (req: Request, res: Response) => {
  try {
    const { identity, password } = req.body; // identity can be username or email

    if (!identity || !password) {
      return res.status(400).json({ error: "Identity (username/email) and password are required." });
    }

    const db = await getDb();

    // Find user
    const user = await db.get(
      "SELECT * FROM users WHERE username = ? OR email = ?",
      [identity.toLowerCase(), identity.toLowerCase()]
    );

    if (!user) {
      return res.status(401).json({ error: "Invalid credentials." });
    }

    if (!user.is_active) {
      return res.status(403).json({ error: "Account is deactivated." });
    }

    // Verify Password
    const isPasswordValid = await comparePassword(password, user.password_hash);
    if (!isPasswordValid) {
      return res.status(401).json({ error: "Invalid credentials." });
    }

    // Generate Tokens
    const payload = { userId: user.id, username: user.username };
    const accessToken = generateAccessToken(payload);
    const refreshToken = generateRefreshToken(payload);

    // Save refresh token to db
    const sessionId = crypto.randomUUID();
    const expiresAt = new Date();
    expiresAt.setDate(expiresAt.getDate() + 30); // 30 days expiration

    await db.run(
      "INSERT INTO user_sessions (id, user_id, refresh_token, expires_at) VALUES (?, ?, ?, ?)",
      [sessionId, user.id, refreshToken, expiresAt.toISOString()]
    );

    // Get Player Profile
    const profile = await db.get(
      "SELECT resonance_level, gold, experience FROM player_profiles WHERE user_id = ?",
      [user.id]
    );

    return res.status(200).json({
      accessToken,
      refreshToken,
      user: {
        id: user.id,
        username: user.username,
        email: user.email
      },
      profile: profile || null
    });

  } catch (error: any) {
    console.error("Login error:", error);
    return res.status(500).json({ error: "Internal server error during login." });
  }
});

// Endpoint: REFRESH TOKEN
authRouter.post("/refresh", async (req: Request, res: Response) => {
  try {
    const { refreshToken } = req.body;

    if (!refreshToken) {
      return res.status(400).json({ error: "Refresh token is required." });
    }

    const payload = verifyRefreshToken(refreshToken);
    if (!payload) {
      return res.status(401).json({ error: "Invalid or expired refresh token." });
    }

    const db = await getDb();

    // Verify refresh token exists in database and is not expired
    const session = await db.get(
      "SELECT * FROM user_sessions WHERE refresh_token = ?",
      [refreshToken]
    );

    if (!session) {
      return res.status(401).json({ error: "Session not found." });
    }

    const expiryDate = new Date(session.expires_at);
    if (expiryDate.getTime() < Date.now()) {
      // Clean up expired session
      await db.run("DELETE FROM user_sessions WHERE refresh_token = ?", [refreshToken]);
      return res.status(401).json({ error: "Refresh token has expired." });
    }

    // Generate new access token
    const newAccessToken = generateAccessToken({
      userId: payload.userId,
      username: payload.username
    });

    return res.status(200).json({
      accessToken: newAccessToken
    });

  } catch (error: any) {
    console.error("Refresh token error:", error);
    return res.status(500).json({ error: "Internal server error during session refresh." });
  }
});

// Endpoint: ME (Get current user and profile)
authRouter.get("/me", async (req: Request, res: Response) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith("Bearer ")) {
      return res.status(401).json({ error: "Missing or invalid authorization header." });
    }

    const token = authHeader.split(" ")[1];
    const payload = verifyAccessToken(token);

    if (!payload) {
      return res.status(401).json({ error: "Invalid or expired access token." });
    }

    const db = await getDb();
    
    const user = await db.get("SELECT id, username, email FROM users WHERE id = ?", [payload.userId]);
    if (!user) {
      return res.status(404).json({ error: "User not found." });
    }

    const profile = await db.get(
      "SELECT resonance_level, gold, experience FROM player_profiles WHERE user_id = ?",
      [payload.userId]
    );

    return res.status(200).json({
      user,
      profile: profile || null
    });
  } catch (error: any) {
    console.error("Me endpoint error:", error);
    return res.status(500).json({ error: "Internal server error fetching profile." });
  }
});
