const { User } = require('../models');
const { findValidTokenByValue } = require('../modules/users/apiTokenService');

const getBearerToken = (req) => {
    const authHeader = req.headers?.authorization || '';
    const [scheme, token] = authHeader.split(' ');
    if (scheme && token && scheme.toLowerCase() === 'bearer') {
        return token.trim();
    }
    return null;
};

const requireAuth = async (req, res, next) => {
    try {
        // Skip authentication for health check, login routes, and current_user
        const skipPaths = ['/api/health', '/api/login', '/api/current_user'];
        if (skipPaths.includes(req.path) || req.originalUrl === '/api/health') {
            return next();
        }

        if (req.session && req.session.userId) {
            const user = await User.findByPk(req.session.userId);
            if (!user) {
                req.session.destroy();
                return res.status(401).json({ error: 'User not found' });
            }
            req.currentUser = user;
            return next();
        }

        const bearerToken = getBearerToken(req);
        if (!bearerToken) {
            return res.status(401).json({ error: 'Authentication required' });
        }

        const apiToken = await findValidTokenByValue(bearerToken);
        if (!apiToken) {
            return res
                .status(401)
                .json({ error: 'Invalid or expired API token' });
        }

        const user = await User.findByPk(apiToken.user_id);
        if (!user) {
            return res.status(401).json({ error: 'User not found' });
        }

        req.currentUser = user;
        req.authToken = apiToken;

        // Update last_used_at asynchronously (non-blocking) to avoid slowing down the request
        // Only update if it hasn't been updated in the last 5 minutes to reduce database writes
        const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
        if (!apiToken.last_used_at || apiToken.last_used_at < fiveMinutesAgo) {
            // Fire and forget - don't await this update
            apiToken.update({ last_used_at: new Date() }).catch((err) => {
                console.error('Failed to update token last_used_at:', err);
            });
        }

        next();
    } catch (error) {
        console.error('Authentication error:', error);
        res.status(500).json({ error: 'Authentication error' });
    }
};

module.exports = {
    requireAuth,
};
