const jwt = require('jsonwebtoken');
const { User } = require('../models');

/**
 * Authentication middleware
 * Verifies JWT token and attaches user to request
 */
const authenticateToken = async (req, res, next) => {
    try {
        const authHeader = req.headers['authorization'];
        const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

        if (!token) {
            return res.status(401).json({ 
                success: false, 
                message: 'Access token required' 
            });
        }

        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const user = await User.findByPk(decoded.userId, {
            attributes: { exclude: ['password'] }
        });

        if (!user || !user.isActive) {
            return res.status(401).json({ 
                success: false, 
                message: 'Invalid or inactive user' 
            });
        }

        req.user = user;
        next();
    } catch (error) {
        console.error('Token verification error:', error);
        return res.status(403).json({ 
            success: false, 
            message: 'Invalid token' 
        });
    }
};

/**
 * Session-based authentication middleware
 * For web pages using sessions
 */
const authenticateSession = async (req, res, next) => {
    try {
        if (!req.session.userId) {
            req.flash('error', '로그인이 필요합니다.');
            return res.redirect('/auth/login');
        }

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

        if (!user || !user.isActive) {
            req.session.destroy();
            req.flash('error', '유효하지 않은 사용자입니다.');
            return res.redirect('/auth/login');
        }

        req.user = user;
        res.locals.user = user;
        next();
    } catch (error) {
        console.error('Session authentication error:', error);
        req.session.destroy();
        req.flash('error', '인증 오류가 발생했습니다.');
        return res.redirect('/auth/login');
    }
};

/**
 * Admin role middleware
 * Requires user to be authenticated and have admin role
 */
const requireAdmin = (req, res, next) => {
    if (!req.user) {
        return res.status(401).json({ 
            success: false, 
            message: 'Authentication required' 
        });
    }

    if (req.user.role !== 'admin') {
        return res.status(403).json({ 
            success: false, 
            message: 'Admin access required' 
        });
    }

    next();
};

/**
 * Admin session middleware for web pages
 */
const requireAdminSession = (req, res, next) => {
    if (!req.user) {
        req.flash('error', '로그인이 필요합니다.');
        return res.redirect('/auth/login');
    }

    if (req.user.role !== 'admin') {
        req.flash('error', '관리자 권한이 필요합니다.');
        return res.redirect('/');
    }

    next();
};

/**
 * Optional authentication middleware
 * Attaches user if token exists but doesn't require it
 */
const optionalAuth = async (req, res, next) => {
    try {
        // Check session first
        if (req.session.userId) {
            const user = await User.findByPk(req.session.userId, {
                attributes: { exclude: ['password'] }
            });
            if (user && user.isActive) {
                req.user = user;
                res.locals.user = user;
            }
        }

        // Check JWT token if no session
        if (!req.user) {
            const authHeader = req.headers['authorization'];
            const token = authHeader && authHeader.split(' ')[1];

            if (token) {
                const decoded = jwt.verify(token, process.env.JWT_SECRET);
                const user = await User.findByPk(decoded.userId, {
                    attributes: { exclude: ['password'] }
                });
                
                if (user && user.isActive) {
                    req.user = user;
                    res.locals.user = user;
                }
            }
        }

        next();
    } catch (error) {
        // Continue without authentication if token is invalid
        next();
    }
};

module.exports = {
    authenticateToken,
    authenticateSession,
    requireAdmin,
    requireAdminSession,
    optionalAuth
};