import { Request, Response, NextFunction } from 'express';

// Extend the Request interface to include the 'user' property
declare global {
    namespace Express {
        interface Request {
            user?: any;
        }
    }
}
import jwt from 'jsonwebtoken';
import { looksLikeApiKey } from '../utils/apiKeyUtils';
import db from '../models';

const secretKey = process.env.JWT_SECRET || 'your_secret_key';

/**
 * Authenticates requests using either JWT tokens or API keys
 * Supports both formats in Authorization header
 */
export const authenticateToken = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    let token = req.header('Authorization');
    
    if (token && token.startsWith("Bearer ")) {
        token = token.slice(7, token.length);
    }
    
    if (!token) {
        res.status(401).json({ message: 'Access token is missing' });
        return;
    }

    try {
        // Check if token looks like an API key (64 characters)
        if (looksLikeApiKey(token)) {
            await authenticateApiKey(token, req, res, next);
        } else {
            // Handle as JWT token
            jwt.verify(token, secretKey, (err: any, user: any) => {
                if (err) {
                    res.status(403).json({ message: 'Invalid token' });
                    return;
                }
                req.user = user;
                next();
            });
        }
    } catch (error) {
        console.error('Authentication error:', error);
        res.status(500).json({ message: 'Authentication failed' });
    }
};

/**
 * Authenticates using API key and updates last used timestamp
 */
const authenticateApiKey = async (apiKey: string, req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
        const UserModel = db.User;
        
        // Find user by API key
        const user = await UserModel.findOne({
            where: { 
                api_key: apiKey,
                isActive: true 
            },
            attributes: { exclude: ['token'] }
        });

        if (!user) {
            res.status(403).json({ message: 'Invalid API key' });
            return;
        }

        // Update last used timestamp
        await UserModel.update(
            { api_key_last_used: new Date() },
            { where: { id: user.id } }
        );

        // Set user in request object (format similar to JWT payload)
        req.user = {
            user_data: {
                id: user.id,
                first_name: user.first_name,
                last_name: user.last_name,
                email: user.email,
                role_id: user.role_id
            }
        };

        next();
    } catch (error) {
        console.error('API key authentication error:', error);
        res.status(500).json({ message: 'Authentication failed' });
    }
};

export const checkRole = (roles: string[]) => {
    return (req: Request, res: Response, next: NextFunction): void => {
        if (!req.user || !roles.includes(req.user.role)) {
            res.status(403).json({ message: 'Insufficient permissions' });
            return;
        }
        next();
    };
};