import { Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { config } from '../../config/index.js';
import { AuthenticatedRequest, JwtPayload, UnauthorizedError, ForbiddenError } from '../types/index.js';
import { logger } from '../utils/logger.js';

// Re-export AuthenticatedRequest for convenience
export { AuthenticatedRequest } from '../types/index.js';

export function authenticate(
  req: AuthenticatedRequest,
  _res: Response,
  next: NextFunction
): void {
  try {
    const authHeader = req.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new UnauthorizedError('Token de acceso requerido');
    }

    const token = authHeader.substring(7);

    try {
      const payload = jwt.verify(token, config.jwt.secret) as JwtPayload;
      req.user = payload;
      req.tenantId = payload.tenantId;
      next();
    } catch (error) {
      if (error instanceof jwt.TokenExpiredError) {
        throw new UnauthorizedError('Token expirado');
      }
      throw new UnauthorizedError('Token inválido');
    }
  } catch (error) {
    next(error);
  }
}

export function requireRoles(...roles: string[]) {
  return (req: AuthenticatedRequest, _res: Response, next: NextFunction): void => {
    try {
      if (!req.user) {
        throw new UnauthorizedError('Usuario no autenticado');
      }

      // Superusers bypass role checks
      if (req.user.roles.includes('super_admin')) {
        return next();
      }

      const hasRole = roles.some(role => req.user!.roles.includes(role));
      if (!hasRole) {
        logger.warn('Access denied - insufficient roles', {
          userId: req.user.userId,
          requiredRoles: roles,
          userRoles: req.user.roles,
        });
        throw new ForbiddenError('No tiene permisos para esta acción');
      }

      next();
    } catch (error) {
      next(error);
    }
  };
}

export function requirePermission(resource: string, action: string) {
  return async (req: AuthenticatedRequest, _res: Response, next: NextFunction): Promise<void> => {
    try {
      if (!req.user) {
        throw new UnauthorizedError('Usuario no autenticado');
      }

      // Superusers bypass permission checks
      if (req.user.roles.includes('super_admin')) {
        return next();
      }

      // TODO: Check permission in database
      // For now, we'll implement this when we have the permission checking service
      logger.debug('Permission check', {
        userId: req.user.userId,
        resource,
        action,
      });

      next();
    } catch (error) {
      next(error);
    }
  };
}

export function optionalAuth(
  req: AuthenticatedRequest,
  _res: Response,
  next: NextFunction
): void {
  try {
    const authHeader = req.headers.authorization;

    if (authHeader && authHeader.startsWith('Bearer ')) {
      const token = authHeader.substring(7);
      try {
        const payload = jwt.verify(token, config.jwt.secret) as JwtPayload;
        req.user = payload;
        req.tenantId = payload.tenantId;
      } catch {
        // Token invalid, but that's okay for optional auth
      }
    }

    next();
  } catch (error) {
    next(error);
  }
}
