import { Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import db from '../../database/models/index.js';
import logger from '../utils/logger.js';
import { JWT_SECRET } from '../config/auth.js';
import { AuthenticatedRequest, AuthRequest } from '../../types/express.types.js';

export const authenticate = async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
        // Get token from header
        const authHeader = req.header('Authorization');

        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            console.warn(`[Auth] 401: No token provided or invalid format for ${req.method} ${req.path}`);
            return res.status(401).json({
                success: false,
                message: 'Access denied. No token provided.'
            });
        }

        const token = authHeader.replace('Bearer ', '');

        // Mock Prospective User handling
        // Mock Prospective User handling
        if (token.startsWith('mock-prospective-token-')) {
            const appId = token.replace('mock-prospective-token-', '');

            // Validate UUID format to prevent DB errors with legacy tokens
            const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
            if (!uuidRegex.test(appId)) {
                console.warn(`[Auth] 401: Invalid Prospective UUID: ${appId}`);
                return res.status(401).json({
                    success: false,
                    message: 'Invalid session token. Please login again.'
                });
            }

            // Find application to get real details
            const application = await db.Application.findByPk(appId);

            if (application) {
                req.user = {
                    id: application.id,
                    email: application.email,
                    phone: application.phone, // Adding phone here
                    firstName: application.applicantName ? application.applicantName.split(' ')[0] : 'Prospective',
                    lastName: application.applicantName ? application.applicantName.split(' ').slice(1).join(' ') : 'User',
                    fullName: application.applicantName,
                    roleCode: 'Prospective Dealer',
                    status: 'active'
                } as any;
                req.token = token;
                return next();
            }
            // If app not found, fall through or error? 
            // Let's error to be safe as the token was specific
            console.warn(`[Auth] 401: Prospective application not found for ID: ${appId}`);
            return res.status(401).json({
                success: false,
                message: 'Invalid prospective user session.'
            });
        }

        // Verify token
        const decoded = jwt.verify(token, JWT_SECRET) as { userId: string };

        // Find user
        const user = await db.User.findByPk(decoded.userId, {
            attributes: { exclude: ['password'] }
        });

        if (!user) {
            console.warn(`[Auth] 401: User not found for ID: ${decoded.userId}`);
            return res.status(401).json({
                success: false,
                message: 'Invalid token. User not found.'
            });
        }

        if (user.status !== 'active') {
            console.warn(`[Auth] 401: Inactive user tried to access: ${user.id}`);
            return res.status(401).json({
                success: false,
                message: 'User account is inactive.'
            });
        }

        // Attach user to request
        req.user = user;
        req.token = token;

        next();
    } catch (error: any) {
        logger.error('Authentication error:', error);

        if (error.name === 'TokenExpiredError') {
            console.warn(`[Auth] 401: Token Expired`);
            return res.status(401).json({
                success: false,
                message: 'Token expired'
            });
        }

        if (error.name === 'JsonWebTokenError') {
            return res.status(401).json({
                success: false,
                message: 'Invalid token'
            });
        }

        res.status(500).json({
            success: false,
            message: 'Authentication failed'
        });
    }
};

export const optionalAuth = async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
        const authHeader = req.header('Authorization');

        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            return next();
        }

        const token = authHeader.replace('Bearer ', '');
        const decoded = jwt.verify(token, JWT_SECRET) as { userId: string };

        const user = await db.User.findByPk(decoded.userId, {
            attributes: { exclude: ['password'] }
        });

        if (user && user.status === 'active') {
            req.user = user;
            req.token = token;
        }

        next();
    } catch (error) {
        // If token is invalid/expired, just proceed without user
        next();
    }
};
