const jwt = require('jsonwebtoken');
const config = require('../config');
const { Admin, AdminSession, ApiKey } = require('../models');
const { UnauthorizedError, ForbiddenError } = require('../utils/errors');
const logger = require('../utils/logger');

/**
 * Authenticate admin via JWT token
 */
const authenticateAdmin = async (req, res, next) => {
  try {
    let token;

    // Get token from header
    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
      token = req.headers.authorization.split(' ')[1];
    }

    if (!token) {
      throw new UnauthorizedError('Access denied. No token provided.');
    }

    // Verify token
    const decoded = jwt.verify(token, config.jwt.secret);

    // Check if admin exists
    const admin = await Admin.findByPk(decoded.id);
    if (!admin) {
      throw new UnauthorizedError('Admin not found.');
    }
    
   
    // Check if admin is active
    if (admin.status !== 'active') {
      throw new ForbiddenError('Account is not active.');
    }

     const roles = ['admin' , 'superadmin']
    if (!roles.includes(admin.role)) {
       throw new ForbiddenError('You are not autorized to view this.');
    }

    // Check if password was changed after token was issued
    if (admin.changedPasswordAfter(decoded.iat)) {
      throw new UnauthorizedError('Password recently changed. Please log in again.');
    }

    // Verify session is still valid
    if (decoded.sessionId) {
      const session = await AdminSession.findByPk(decoded.sessionId);
      if (!session || !session.isActive) {
        throw new UnauthorizedError('AdminSession expired. Please log in again.');
      }
      // Update session activity
      await session.updateActivity();
    }

    // Attach admin to request
    req.admin = admin;
    req.token = token;
    req.getBaseUrl = req.protocol + '://' + req.get('host');
    req.sessionId = decoded.sessionId;

    next();
  } catch (error) {
    if (error.name === 'JsonWebTokenError') {
      return next(new UnauthorizedError('Invalid token.'));
    }
    if (error.name === 'TokenExpiredError') {
      return next(new UnauthorizedError('Token expired.'));
    }
    next(error);
  }
};

/**
 * Authenticate via API key
 */


/**
 * Check if admin has required role
 */
const requireAdminRole = (...roles) => {
  return (req, res, next) => {
    if (!req.admin) {
      return next(new UnauthorizedError('Authentication required.'));
    }

    if (!roles.includes(req.admin.role)) {
      return next(new ForbiddenError('Insufficient permissions.'));
    }

    next();
  };
};

/**
 * Check if admin has required permission (for API keys)
 */
const requireAdminPermission = (permission) => {
  return (req, res, next) => {
    if (req.apiKey && !req.apiKey.hasPermission(permission)) {
      return next(new ForbiddenError(`API key lacks '${permission}' permission.`));
    }
    next();
  };
};



/**
 * Check if 2FA is enabled and verified
 */
const requireAdmin2FA = async (req, res, next) => {
  if (!req.admin) {
    return next(new UnauthorizedError('Authentication required.'));
  }

  if (req.admin.twoFactorEnabled && !req.session?.twoFactorVerified) {
    return next(new ForbiddenError('Two-factor authentication required.'));
  }

  next();
};

/**
 * Optional authentication (attach admin if token present)
 */
const optionalAdminAuth = async (req, res, next) => {
  try {
    let token;

    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
      token = req.headers.authorization.split(' ')[1];
    }

    if (token) {
      const decoded = jwt.verify(token, config.jwt.secret);
      const admin = await Admin.findByPk(decoded.id);
      if (admin && admin.status === 'active') {
        req.admin = admin;
      }
    }

    next();
  } catch (error) {
    // Silent fail - admin just won't be attached
    next();
  }
};

module.exports = {
  authenticateAdmin,
  requireAdminRole,
  requireAdminPermission,
  requireAdmin2FA,
  optionalAdminAuth,
};
