import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { config } from '../config';
import { JWTPayload } from '../types';
import { logger } from '../config/logger';

export interface AuthRequest extends Request {
    user?: JWTPayload;
}

export async function expressAuthentication(
    request: Request,
    securityName: string,
    scopes?: string[]
): Promise<JWTPayload> {
    if (securityName === 'jwt') {
        const token = request.headers.authorization?.replace('Bearer ', '');

        if (!token) {
            throw new Error('No token provided');
        }

        try {
            const decoded = jwt.verify(token, config.jwt.secret) as JWTPayload;

            // Check if user has required role (case-insensitive)
            if (scopes && scopes.length > 0) {
                const userRole = decoded.roleCode.toUpperCase();
                const requiredRoles = scopes.map(scope => scope.toUpperCase());
                if (!requiredRoles.includes(userRole)) {
                    throw new Error('Insufficient permissions');
                }
            }

            return decoded;
        } catch (error) {
            logger.error('JWT verification failed', { error });
            throw new Error('Invalid token');
        }
    }

    throw new Error('Unknown security name');
}

export function authenticate(req: AuthRequest, res: Response, next: NextFunction) {
    const token = req.headers.authorization?.replace('Bearer ', '');

    if (!token) {
        return res.status(401).json({
            error: {
                code: 'UNAUTHORIZED',
                message: 'No token provided'
            }
        });
    }

    try {
        const decoded = jwt.verify(token, config.jwt.secret) as JWTPayload;
        req.user = decoded;
        next();
    } catch (error) {
        logger.error('Authentication failed', { error });
        return res.status(401).json({
            error: {
                code: 'UNAUTHORIZED',
                message: 'Invalid token'
            }
        });
    }
}

export function authorize(...roles: string[]) {
    return (req: AuthRequest, res: Response, next: NextFunction) => {
        if (!req.user) {
            return res.status(401).json({
                error: {
                    code: 'UNAUTHORIZED',
                    message: 'Not authenticated'
                }
            });
        }

        if (roles.length > 0 && !roles.includes(req.user.roleCode)) {
            return res.status(403).json({
                error: {
                    code: 'FORBIDDEN',
                    message: 'Insufficient permissions'
                }
            });
        }

        next();
    };
}
