import { verifyToken, extractTokenFromHeader } from '@goodgo/auth-sdk';
import { logger } from '@goodgo/logger';
import { ApiResponse } from '@goodgo/types';
import { Request, Response, NextFunction } from 'express';

/**
 * EN: Extended Request interface with user information
 * VI: Interface Request mở rộng với thông tin người dùng
 */
declare global {
  namespace Express {
    interface Request {
      user?: {
        userId: string;
        email: string;
        role: string;
        iat?: number;
        exp?: number;
      };
    }
  }
}

/**
 * EN: Authentication middleware - verifies JWT tokens
 * VI: Middleware xác thực - xác minh JWT tokens
 *
 * @param options - Configuration options / Tùy chọn cấu hình
 */
export const authenticate = (options: {
  secret: string;
  ignoreExpiration?: boolean;
} = { secret: process.env.JWT_SECRET || 'default-secret' }) => {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      // EN: Extract token from Authorization header
      // VI: Trích xuất token từ header Authorization
      const token = extractTokenFromHeader(req.headers.authorization);

      if (!token) {
        logger.warn('No authentication token provided / Không có token xác thực được cung cấp', {
          path: req.path,
          method: req.method,
        });

        const response: ApiResponse = {
          success: false,
          error: {
            code: 'AUTH_001',
            message: 'Authentication required / Yêu cầu xác thực',
          },
          timestamp: new Date().toISOString(),
        };
        res.status(401).json(response);
        return;
      }

      // EN: Verify token
      // VI: Xác minh token
      const payload = verifyToken(token, {
        secret: options.secret,
        ignoreExpiration: options.ignoreExpiration,
      });

      // EN: Attach user information to request
      // VI: Gắn thông tin người dùng vào request
      req.user = {
        userId: payload.userId,
        email: payload.email,
        role: payload.role,
        iat: payload.iat,
        exp: payload.exp,
      };

      logger.debug('User authenticated successfully / Người dùng đã được xác thực thành công', {
        userId: payload.userId,
        email: payload.email,
        role: payload.role,
      });

      next();
    } catch (error: any) {
      logger.warn('Authentication failed / Xác thực thất bại', {
        error: error.message,
        path: req.path,
        method: req.method,
      });

      const response: ApiResponse = {
        success: false,
        error: {
          code: 'AUTH_002',
          message: 'Invalid or expired token / Token không hợp lệ hoặc hết hạn',
        },
        timestamp: new Date().toISOString(),
      };
      res.status(401).json(response);
    }
  };
};

/**
 * EN: Role-based authorization middleware
 * VI: Middleware phân quyền dựa trên vai trò
 *
 * @param allowedRoles - Array of roles that can access the resource / Mảng các vai trò được phép truy cập tài nguyên
 */
export const authorize = (...allowedRoles: string[]) => {
  return (req: Request, res: Response, next: NextFunction) => {
    // EN: Check if user is authenticated
    // VI: Kiểm tra người dùng đã được xác thực chưa
    if (!req.user) {
      logger.warn('Authorization attempted without authentication / Phân quyền được thử mà không xác thực', {
        path: req.path,
        method: req.method,
      });

      const response: ApiResponse = {
        success: false,
        error: {
          code: 'AUTH_003',
          message: 'Authentication required / Yêu cầu xác thực',
        },
        timestamp: new Date().toISOString(),
      };
      res.status(401).json(response);
      return;
    }

    // EN: Check if user has required role
    // VI: Kiểm tra người dùng có vai trò cần thiết không
    if (!allowedRoles.includes(req.user.role)) {
      logger.warn('Access denied - insufficient permissions / Truy cập bị từ chối - không đủ quyền', {
        userId: req.user.userId,
        userRole: req.user.role,
        requiredRoles: allowedRoles,
        path: req.path,
        method: req.method,
      });

      const response: ApiResponse = {
        success: false,
        error: {
          code: 'AUTH_004',
          message: 'Insufficient permissions / Không đủ quyền',
        },
        timestamp: new Date().toISOString(),
      };
      res.status(403).json(response);
      return;
    }

    logger.debug('Authorization successful / Phân quyền thành công', {
      userId: req.user.userId,
      userRole: req.user.role,
      path: req.path,
      method: req.method,
    });

    next();
  };
};

/**
 * EN: Combined auth and authorization middleware
 * VI: Middleware kết hợp xác thực và phân quyền
 *
 * @param secret - JWT secret key / Khóa bí mật JWT
 * @param allowedRoles - Array of allowed roles / Mảng vai trò được phép
 */
export const requireAuth = (
  secret: string = process.env.JWT_SECRET || 'default-secret',
  ...allowedRoles: string[]
) => {
  return [authenticate({ secret }), authorize(...allowedRoles)];
};

/**
 * EN: Optional authentication middleware - doesn't fail if no token provided
 * VI: Middleware xác thực tùy chọn - không thất bại nếu không có token
 *
 * @param options - Configuration options / Tùy chọn cấu hình
 */
export const optionalAuth = (options: {
  secret: string;
  ignoreExpiration?: boolean;
} = { secret: process.env.JWT_SECRET || 'default-secret' }) => {
  return (req: Request, _res: Response, next: NextFunction) => {
    try {
      const token = extractTokenFromHeader(req.headers.authorization);

      if (token) {
        const payload = verifyToken(token, {
          secret: options.secret,
          ignoreExpiration: options.ignoreExpiration,
        });

        req.user = {
          userId: payload.userId,
          email: payload.email,
          role: payload.role,
          iat: payload.iat,
          exp: payload.exp,
        };

        logger.debug('Optional authentication successful / Xác thực tùy chọn thành công', {
          userId: payload.userId,
        });
      }

      next();
    } catch (error: any) {
      // EN: For optional auth, just continue without user info
      // VI: Với optional auth, chỉ tiếp tục mà không có thông tin user
      logger.debug('Optional authentication skipped / Xác thực tùy chọn bị bỏ qua', {
        reason: error.message,
      });
      next();
    }
  };
};

/**
 * EN: Check if user has specific role (utility function)
 * VI: Kiểm tra người dùng có vai trò cụ thể (hàm tiện ích)
 *
 * @param user - User object from request / Đối tượng user từ request
 * @param role - Role to check / Vai trò cần kiểm tra
 * @returns True if user has the role / True nếu user có vai trò
 */
export const hasRole = (user: Express.Request['user'], role: string): boolean => {
  return user?.role === role;
};

/**
 * EN: Check if user has any of the specified roles (utility function)
 * VI: Kiểm tra người dùng có bất kỳ vai trò nào trong danh sách (hàm tiện ích)
 *
 * @param user - User object from request / Đối tượng user từ request
 * @param roles - Array of roles to check / Mảng vai trò cần kiểm tra
 * @returns True if user has any of the roles / True nếu user có bất kỳ vai trò nào
 */
export const hasAnyRole = (user: Express.Request['user'], roles: string[]): boolean => {
  return user ? roles.includes(user.role) : false;
};

/**
 * EN: Check if user is authenticated (utility function)
 * VI: Kiểm tra người dùng đã được xác thực (hàm tiện ích)
 *
 * @param user - User object from request / Đối tượng user từ request
 * @returns True if user is authenticated / True nếu user đã được xác thực
 */
export const isAuthenticated = (user: Express.Request['user']): boolean => {
  return !!user;
};