const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const crypto = require('crypto');
const { Op } = require('sequelize');
const { User, Role } = require('../models/foundation');
const { logAction } = require('../utils/logger');
const notificationService = require('../services/notificationService');

exports.login = async (req, res) => {
    const { email, password } = req.body;
    console.log('Login attempt for:', email);

    try {
        const user = await User.findOne({
            where: { email },
            include: [{ model: Role }]
        });

        if (!user) {
            console.log('Login failed: User not found');
            return res.status(401).json({ message: 'Invalid credentials' });
        }

        const isMatch = await bcrypt.compare(password, user.password);
        console.log(`Password check for ${email}: ${isMatch ? 'MATCH' : 'NO MATCH'}`);

        if (!isMatch) {
            console.log('Login failed: Password mismatch');
            return res.status(401).json({ message: 'Invalid credentials' });
        }

        if (!user.isActive) {
            console.log('Login failed: User inactive');
            return res.status(403).json({ message: 'Account deactivated' });
        }

        const token = jwt.sign(
            { id: user.id, role: user.Role.constant, clientId: user.clientId, fullName: user.fullName },
            process.env.JWT_SECRET,
            { expiresIn: process.env.JWT_EXPIRES_IN }
        );

        // Update last login
        user.lastLogin = new Date();
        await user.save();

        await logAction(user.id, 'LOGIN', 'AUTH', 'User logged in successfully', req.ip);

        console.log('Login successful for:', email);
        res.json({
            token,
            user: {
                id: user.id,
                fullName: user.fullName,
                email: user.email,
                role: user.Role.constant,
                clientId: user.clientId,
                mustChangePassword: user.mustChangePassword
            }
        });
    } catch (err) {
        console.error('Login error:', err);
        res.status(500).json({ error: err.message });
    }
};

exports.getMe = async (req, res) => {
    try {
        const user = await User.findByPk(req.user.id, {
            include: [{ model: Role }],
            attributes: { exclude: ['password'] }
        });
        res.json(user);
    } catch (err) {
        res.status(500).json({ error: err.message });
    }
};

exports.changePassword = async (req, res) => {
    try {
        const { currentPassword, newPassword } = req.body;
        const user = await User.findByPk(req.user.id);

        const isMatch = await bcrypt.compare(currentPassword, user.password);
        if (!isMatch) {
            return res.status(400).json({ message: 'Current password incorrect' });
        }

        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(newPassword, salt);
        user.mustChangePassword = false;
        await user.save();

        await logAction(user.id, 'CHANGE_PASSWORD', 'AUTH', 'User changed their password', req.ip);
        res.json({ message: 'Password changed successfully' });
    } catch (err) {
        res.status(500).json({ error: err.message });
    }
};
exports.requestReset = async (req, res) => {
    const { identity } = req.body; // email or phone
    if (!identity) return res.status(400).json({ message: 'Email or phone required' });

    try {
        const user = await User.findOne({
            where: {
                [Op.or]: [{ email: identity }, { phone: identity }]
            }
        });

        // Security: Do NOT expose whether a user exists
        if (!user) {
            return res.json({ message: 'If an account exists, instructions have been sent.' });
        }

        if (identity.includes('@')) {
            // Email Reset
            const token = crypto.randomBytes(32).toString('hex');
            user.resetToken = token;
            user.tokenExpiry = new Date(Date.now() + 15 * 60 * 1000); // 15 mins
            await user.save();
            await notificationService.sendPasswordResetLink(user, token);
        } else {
            // SMS Reset
            const otp = Math.floor(100000 + Math.random() * 900000).toString();
            user.otp = otp;
            user.otpExpiry = new Date(Date.now() + 10 * 60 * 1000); // 10 mins
            await user.save();
            await notificationService.sendPasswordResetOTP(user, otp);
        }

        await logAction(user.id, 'REQUEST_RESET', 'AUTH', `Reset requested via ${identity.includes('@') ? 'Email' : 'SMS'}`, req.ip);
        res.json({ message: 'If an account exists, instructions have been sent.' });
    } catch (err) {
        console.error('Reset request error:', err);
        res.status(500).json({ error: err.message });
    }
};

exports.verifyReset = async (req, res) => {
    const { identity, token, otp, newPassword } = req.body;

    try {
        const user = await User.findOne({
            where: {
                [Op.or]: [{ email: identity }, { phone: identity }]
            }
        });

        if (!user) return res.status(400).json({ message: 'Invalid or expired request' });

        let isValid = false;
        if (token) {
            isValid = user.resetToken === token && user.tokenExpiry > new Date();
        } else if (otp) {
            isValid = user.otp === otp && user.otpExpiry > new Date();
        }

        if (!isValid) {
            await logAction(user.id, 'RESET_FAILED', 'AUTH', 'Invalid token or OTP attempt', req.ip);
            return res.status(400).json({ message: 'Invalid or expired request' });
        }

        // Single-use: clear token/otp
        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(newPassword, salt);
        user.resetToken = null;
        user.tokenExpiry = null;
        user.otp = null;
        user.otpExpiry = null;
        user.mustChangePassword = false;
        await user.save();

        await logAction(user.id, 'RESET_SUCCESS', 'AUTH', 'Password reset successfully', req.ip);
        res.json({ message: 'Password has been reset successfully' });
    } catch (err) {
        console.error('Reset verification error:', err);
        res.status(500).json({ error: err.message });
    }
};
