const jwt = require("jsonwebtoken");
const { User } = require("../models"); // Import from models/index.js to get models with associations
const logger = require("../utils/logger");

const authenticateToken = async (req, res, next) => {
  // First try to get token from cookie
  let token = req.cookies?.accessToken;

  if (!token) {
    return res.status(401).json({
      error: "Access token required",
      code: "NO_TOKEN",
    });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_ACCESS_SECRET);
    const userId = decoded.id;

    if (!userId) {
      return res.status(401).json({
        error: "Invalid token format",
        code: "INVALID_TOKEN_FORMAT",
      });
    }

    const user = await User.findByPk(userId);

    if (!user) {
      return res.status(401).json({
        error: "User not found",
        code: "USER_NOT_FOUND",
      });
    }

    // Check if user is banned
    if (user.isBanned) {
      return res.status(403).json({
        error: "Your account has been suspended. Please contact support for more information.",
        code: "USER_BANNED",
      });
    }

    // Validate JWT version to invalidate old tokens after password change
    if (decoded.jwtVersion !== user.jwtVersion) {
      return res.status(401).json({
        error: "Session expired due to password change. Please log in again.",
        code: "JWT_VERSION_MISMATCH",
      });
    }

    req.user = user;
    next();
  } catch (error) {
    // Check if token is expired
    if (error.name === "TokenExpiredError") {
      return res.status(401).json({
        error: "Token expired",
        code: "TOKEN_EXPIRED",
      });
    }

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Auth middleware error", {
      error: error.message,
      stack: error.stack,
      tokenPresent: !!token,
      userId: req.user?.id
    });
    return res.status(403).json({
      error: "Invalid token",
      code: "INVALID_TOKEN",
    });
  }
};

// Optional authentication - doesn't return 401 if no token, just continues
const optionalAuth = async (req, res, next) => {
  // Try to get token from cookie
  let token = req.cookies?.accessToken;

  if (!token) {
    // No token is fine for optional auth, just continue
    req.user = null;
    return next();
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_ACCESS_SECRET);
    const userId = decoded.id;

    if (!userId) {
      req.user = null;
      return next();
    }

    const user = await User.findByPk(userId);

    if (!user) {
      req.user = null;
      return next();
    }

    // Banned users are treated as unauthenticated for optional auth
    if (user.isBanned) {
      req.user = null;
      return next();
    }

    // Validate JWT version to invalidate old tokens after password change
    if (decoded.jwtVersion !== user.jwtVersion) {
      req.user = null;
      return next();
    }

    req.user = user;
    next();
  } catch (error) {
    // Token invalid/expired is fine for optional auth
    req.user = null;
    next();
  }
};

// Require verified email middleware - must be used after authenticateToken
const requireVerifiedEmail = (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({
      error: "Authentication required",
      code: "NO_AUTH",
    });
  }

  if (!req.user.isVerified) {
    return res.status(403).json({
      error: "Email verification required. Please verify your email address to perform this action.",
      code: "EMAIL_NOT_VERIFIED",
    });
  }

  next();
};

// Require admin role middleware - must be used after authenticateToken
const requireAdmin = (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({
      error: "Authentication required",
      code: "NO_AUTH",
    });
  }

  if (req.user.role !== "admin") {
    return res.status(403).json({
      error: "Admin access required",
      code: "INSUFFICIENT_PERMISSIONS",
    });
  }

  next();
};

module.exports = { authenticateToken, optionalAuth, requireVerifiedEmail, requireAdmin };
