import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken'; 
import nodemailer from 'nodemailer';
import { Op } from 'sequelize';
import transporter from '../config/mail.js';
import { User, Settings } from '../models/index.js';
import { defaultPermissions } from '../models/usermanagement.model.js';

const getFullPermissions = () => {
    const permissions = {};

    Object.keys(defaultPermissions).forEach((moduleName) => {
        permissions[moduleName] = { view: true };
    });

    return permissions;
};

const buildAuthUserResponse = (user) => ({
    id: user.id,
    name: user.name,
    email: user.email,
    role: user.role,
    status: user.status,
    avatar: user.avatar,
    permissions: user.role === 'admin' ? getFullPermissions() : user.permissions
});

// ================= CREATE ACCOUNT =================

export const createAccount = async (req, res) => {
    try {
        const { name, email, password } = req.body;


        if (!name || !email || !password) {
            return res.status(400).json({
                success: false,
                message: 'Please fill all fields'
            });
        }

        const existingUser = await User.findOne({
            where: {
                [Op.or]: [
                    { email },
                    { name }
                ]
            }
        });

        if (existingUser) {
            const message = existingUser.email === email
                ? 'Email already exists'
                : 'Name already exists';

            return res.status(400).json({
                success: false,
                message
            });
        }


        const hashedPassword = await bcrypt.hash(password, 10);


        const user = await User.create({
            name,
            email,
            password: hashedPassword,
            role: 'admin'
        });

        const token = jwt.sign(
            { id: user.id, email: user.email },
            process.env.JWT_SECRET,
            { expiresIn: '1d' }
        );

        res.status(201).json({
            success: true,
            message: 'Account created successfully',
            token,
            user: buildAuthUserResponse(user)
        });

    } catch (error) {
        console.log(error);

        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
};


// ================= LOGIN =================
export const login = async (req, res) => {
    try {
        const { email, password } = req.body;

        if (!email || !password) {
            return res.status(400).json({
                success: false,
                message: 'Please provide email and password'
            });
        }


        const user = await User.findOne({
            where: { email }
        });

        if (!user) {
            return res.status(400).json({
                success: false,
                message: 'Invalid email or password'
            });
        }

        const isMatch = await bcrypt.compare(password, user.password);

        if (!isMatch) {
            return res.status(400).json({
                success: false,
                message: 'Invalid email or password'
            });
        }

   
        const token = jwt.sign(
            { id: user.id, email: user.email }, 
            process.env.JWT_SECRET, 
            { expiresIn: '1d' } 
        );

     
        res.status(200).json({
            success: true,
            message: 'Login successful',
            token, 
            user: buildAuthUserResponse(user)
        });

    } catch (error) {
        console.log(error);
        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
};

// ================= FORGET PASSWORD =================

export const forgetPassword = async (req, res) => {
    try {
        const { email } = req.body;

        if (!email) {
            return res.status(400).json({
                success: false,
                message: 'Please provide email'
            });
        }

        const user = await User.findOne({
            where: { email }
        });

        if (!user) {
            return res.status(400).json({
                success: false,
                message: 'Email not found'
            });
        }

        const clientUrl = process.env.CLIENT_URL || 'http://localhost:3000';
        const resetLink = `${clientUrl}/reset-password?email=${encodeURIComponent(email)}`;

        let settings = null;
        try {
            settings = await Settings.findOne();
        } catch (error) {
            settings = null;
        }

        const senderEmail = settings?.smtp_from_email || settings?.smtp_user || process.env.SMTP_USER || process.env.EMAIL_USER || 'no-reply@example.com';
        const senderName = settings?.smtp_from_name || process.env.SMTP_FROM_NAME || 'Deytal Dashboard';

        const mailOptions = {
            from: senderName ? `${senderName} <${senderEmail}>` : senderEmail,
            to: email,
            subject: 'Password reset link',
            html: `<p>Hello ${user.name || ''},</p>
                   <p>We received a request to reset your password. Click the link below to reset it:</p>
                   <p><a href="${resetLink}">${resetLink}</a></p>
                   <p>If you didn't request this, please ignore this email.</p>`
        };

        const info = await transporter.sendMail(mailOptions);

        const responsePayload = {
            success: true,
            message: 'Password reset link sent to email'
        };

        const previewUrl = nodemailer.getTestMessageUrl(info);
        if (previewUrl) responsePayload.previewUrl = previewUrl;

        res.status(200).json(responsePayload);

    } catch (error) {
        console.log(error);

        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
};

// ================= RESET PASSWORD =================

export const resetPassword = async (req, res) => {
    try {
        const { email, newPassword } = req.body;

        if (!email || !newPassword) {
            return res.status(400).json({
                success: false,
                message: 'Please provide email and new password'
            });
        }


        const user = await User.findOne({
            where: { email }
        });

        if (!user) {
            return res.status(400).json({
                success: false,
                message: 'Email not found'
            });
        }

        const hashedPassword = await bcrypt.hash(newPassword, 10);

        await user.update({
            password: hashedPassword
        });

        res.status(200).json({
            success: true,
            message: 'Password reset successful'
        });

    } catch (error) {
        console.log(error);

        res.status(500).json({
            success: false,
            message: 'Internal server error'
        });
    }
};
