const express = require("express");
const bcrypt = require("bcrypt");
const { query } = require("../config/database");
const { requireAuth, requireRole } = require("../middleware/auth");
const { apiLimiter } = require("../config/rateLimiter");
const logger = require("../config/logger");
const {
  validators,
  handleValidationErrors,
} = require("../middleware/validators");
const { asyncHandler } = require("../middleware/errorHandler");
const router = express.Router();

// Apply rate limiting
router.use(apiLimiter);

// Require admin role for all routes
router.use(requireAuth);
router.use(requireRole("role-admin"));

// Get all users with roles
router.get("/", async (req, res) => {
  try {
    const result = await query(`
      SELECT 
        u.id, u.username, u.email, u.name, u.role, u.isactive, 
        u.last_login, u.createdat, u.passwordneverexpires
      FROM adminusers u
      ORDER BY u.createdat DESC
    `);

    res.json({
      success: true,
      users: result.rows,
    });
  } catch (error) {
    logger.error("Get users error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Get all roles
router.get("/roles", async (req, res) => {
  try {
    const result = await query(`
      SELECT id, name, description, permissions
      FROM roles
      ORDER BY name
    `);

    res.json({
      success: true,
      roles: result.rows,
    });
  } catch (error) {
    logger.error("Get roles error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Get single user by ID
router.get("/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const result = await query(
      `
      SELECT 
        u.id, u.username, u.email, u.name, u.role, u.isactive, 
        u.last_login, u.createdat, u.passwordneverexpires, u.role_id
      FROM adminusers u
      WHERE u.id = $1
    `,
      [id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    res.json({
      success: true,
      user: result.rows[0],
    });
  } catch (error) {
    logger.error("Get user error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Create new user
router.post("/", async (req, res) => {
  try {
    const { name, username, email, password, role, passwordneverexpires } =
      req.body;

    // Validate required fields
    if (!username || !email || !password || !role) {
      return res.status(400).json({
        success: false,
        message: "Name, username, email, password, and role are required",
      });
    }

    // Check if user already exists
    const existing = await query(
      "SELECT id FROM adminusers WHERE email = $1 OR username = $2",
      [email, username]
    );

    if (existing.rows.length > 0) {
      return res.status(400).json({
        success: false,
        message: "User with this email or username already exists",
      });
    }

    // Hash password with bcrypt (10 rounds)
    const hashedPassword = await bcrypt.hash(password, 10);

    // Calculate password expiry (90 days from now if not never expires)
    let passwordExpiresAt = null;
    if (!passwordneverexpires) {
      const expiryDate = new Date();
      expiryDate.setDate(expiryDate.getDate() + 90);
      passwordExpiresAt = expiryDate.toISOString();
    }

    // Insert new user with both role and name fields
    const result = await query(
      `
      INSERT INTO adminusers (
        id, name, username, email, passwordhash, role, 
        passwordneverexpires, password_expires_at, 
        isactive, created_by, createdat, lastpasswordchange
      ) VALUES (
        'user-' || gen_random_uuid()::text,
        $1, $2, $3, $4, $5, $6, $7, true, $8, NOW(), NOW()
      )
      RETURNING id, name, username, email, role, isactive, createdat, passwordneverexpires
    `,
      [
        name || username,
        username,
        email,
        hashedPassword,
        role,
        passwordneverexpires || false,
        passwordExpiresAt,
        req.session.user.email,
      ]
    );

    res.json({
      success: true,
      message: "User created successfully",
      user: result.rows[0],
    });
  } catch (error) {
    logger.error("Create user error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Update user
router.put("/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const {
      name,
      username,
      email,
      role,
      isactive,
      passwordneverexpires,
      password,
    } = req.body;

    // Build update query dynamically
    const updates = [];
    const values = [];
    let paramCount = 1;

    if (name !== undefined) {
      updates.push(`name = $${paramCount++}`);
      values.push(name);
    }
    if (username !== undefined) {
      updates.push(`username = $${paramCount++}`);
      values.push(username);
    }
    if (email !== undefined) {
      updates.push(`email = $${paramCount++}`);
      values.push(email);
    }
    if (role !== undefined) {
      updates.push(`role = $${paramCount++}`);
      values.push(role);
    }
    if (isactive !== undefined) {
      updates.push(`isactive = $${paramCount++}`);
      values.push(isactive);
    }
    if (passwordneverexpires !== undefined) {
      updates.push(`passwordneverexpires = $${paramCount++}`);
      values.push(passwordneverexpires);

      // If setting to never expire, clear expiry date
      if (passwordneverexpires) {
        updates.push(`password_expires_at = NULL`);
      }
    }

    // Handle password update if provided
    if (password !== undefined && password !== "") {
      // Validate password strength
      if (password.length < 12) {
        return res.status(400).json({
          success: false,
          message: "Password must be at least 12 characters long",
        });
      }

      // Check password complexity
      const hasUpperCase = /[A-Z]/.test(password);
      const hasLowerCase = /[a-z]/.test(password);
      const hasNumber = /\d/.test(password);
      const hasSpecialChar = /[@$!%*?&#]/.test(password);

      if (!hasUpperCase || !hasLowerCase || !hasNumber || !hasSpecialChar) {
        return res.status(400).json({
          success: false,
          message:
            "Password must contain uppercase, lowercase, number, and special character",
        });
      }

      const hashedPassword = await bcrypt.hash(password, 10);
      updates.push(`passwordhash = $${paramCount++}`);
      values.push(hashedPassword);
      updates.push(`lastpasswordchange = NOW()`);
    }

    updates.push(`updatedat = NOW()`);
    values.push(id);

    const result = await query(
      `
      UPDATE adminusers
      SET ${updates.join(", ")}
      WHERE id = $${paramCount}
      RETURNING id, name, username, email, role, isactive, passwordneverexpires
    `,
      values
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    res.json({
      success: true,
      message: "User updated successfully",
      user: result.rows[0],
    });
  } catch (error) {
    logger.error("Update user error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Change user password (PUT endpoint for password modal)
router.put("/:id/password", async (req, res) => {
  try {
    const { id } = req.params;
    const { password } = req.body;

    if (!password || password.length < 8) {
      return res.status(400).json({
        success: false,
        message: "Password must be at least 8 characters long",
      });
    }

    // Hash new password with bcrypt (10 rounds)
    const hashedPassword = await bcrypt.hash(password, 10);

    // Get user's password expiry setting
    const userResult = await query(
      "SELECT passwordneverexpires FROM adminusers WHERE id = $1",
      [id]
    );

    if (userResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    // Calculate new expiry date (90 days from now if not never expires)
    let passwordExpiresAt = null;
    if (!userResult.rows[0].passwordneverexpires) {
      const expiryDate = new Date();
      expiryDate.setDate(expiryDate.getDate() + 90);
      passwordExpiresAt = expiryDate.toISOString();
    }

    // Update password
    await query(
      `
      UPDATE adminusers
      SET passwordhash = $1,
          password_expires_at = $2,
          lastpasswordchange = NOW(),
          updatedat = NOW()
      WHERE id = $3
    `,
      [hashedPassword, passwordExpiresAt, id]
    );

    res.json({
      success: true,
      message: "Password changed successfully",
    });
  } catch (error) {
    logger.error("Change password error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Reset user password
router.post("/:id/reset-password", async (req, res) => {
  try {
    const { id } = req.params;
    const { new_password } = req.body;

    if (!new_password || new_password.length < 6) {
      return res.status(400).json({
        success: false,
        message: "Password must be at least 6 characters long",
      });
    }

    // Hash new password with bcrypt (10 rounds)
    const hashedPassword = await bcrypt.hash(new_password, 10);

    // Get user's password expiry setting
    const userResult = await query(
      "SELECT password_never_expires FROM adminusers WHERE id = $1",
      [id]
    );

    if (userResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    // Calculate new expiry date (90 days from now if not never expires)
    let passwordExpiresAt = null;
    if (!userResult.rows[0].password_never_expires) {
      const expiryDate = new Date();
      expiryDate.setDate(expiryDate.getDate() + 90);
      passwordExpiresAt = expiryDate.toISOString();
    }

    // Update password
    await query(
      `
      UPDATE adminusers
      SET passwordhash = $1,
          password_expires_at = $2,
          last_password_change = NOW(),
          updated_at = NOW()
      WHERE id = $3
    `,
      [hashedPassword, passwordExpiresAt, id]
    );

    res.json({
      success: true,
      message: "Password reset successfully",
    });
  } catch (error) {
    logger.error("Reset password error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Delete user
router.delete("/:id", async (req, res) => {
  try {
    const { id } = req.params;

    // Prevent deleting yourself
    if (id === req.session.user.id) {
      return res.status(400).json({
        success: false,
        message: "Cannot delete your own account",
      });
    }

    const result = await query(
      "DELETE FROM adminusers WHERE id = $1 RETURNING id",
      [id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    res.json({
      success: true,
      message: "User deleted successfully",
    });
  } catch (error) {
    logger.error("Delete user error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

// Toggle user active status
router.post("/:id/toggle-status", async (req, res) => {
  try {
    const { id } = req.params;

    // Prevent deactivating yourself
    if (id === req.session.user.id) {
      return res.status(400).json({
        success: false,
        message: "Cannot deactivate your own account",
      });
    }

    const result = await query(
      `
      UPDATE adminusers
      SET isactive = NOT isactive,
          updated_at = NOW()
      WHERE id = $1
      RETURNING id, isactive
    `,
      [id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: "User not found",
      });
    }

    res.json({
      success: true,
      message: `User ${
        result.rows[0].isactive ? "activated" : "deactivated"
      } successfully`,
      isactive: result.rows[0].isactive,
    });
  } catch (error) {
    logger.error("Toggle status error:", error);
    res.status(500).json({ success: false, message: "Server error" });
  }
});

module.exports = router;
