import fs from 'fs';
import path from 'path';
import { Op } from 'sequelize';
import { Expense } from '../models/index.js';

const allowedCategories = [
    'infrastructure',
    'marketing',
    'travel',
    'utilities',
    'office',
    'salary',
    'other'
];

const allowedStatuses = [
    'pending',
    'approved',
    'rejected'
];




// ================= CREATE EXPENSE =================

export const createExpense = async (req, res) => {

    try {

        const {
            expense_name,
            category,
            amount,
            expense_date,
            vendor,
            payment_method,
            status
        } = req.body;



        // ================= IMAGE / RECEIPT =================

        const receipt = req.file
            ? req.file.filename
            : null;



        // ================= VALIDATIONS =================

        if (
            !expense_name ||
            !category ||
            !amount ||
            !expense_date
        ) {

            // uploaded file delete
            if (req.file) {

                const filePath = path.join(
                    'uploads',
                    req.file.filename
                );

                if (fs.existsSync(filePath)) {
                    fs.unlinkSync(filePath);
                }
            }

            return res.status(400).json({
                success: false,
                message: 'Expense name, category, amount and expense date are required'
            });
        }



        // ================= DUPLICATE RECEIPT CHECK =================

        if (req.file) {

            const existingReceipt = await Expense.findOne({
                where: {
                    receipt: req.file.filename
                }
            });



            if (existingReceipt) {

                // delete uploaded duplicate image

                const filePath = path.join(
                    'uploads',
                    req.file.filename
                );

                if (fs.existsSync(filePath)) {
                    fs.unlinkSync(filePath);
                }



                return res.status(400).json({
                    success: false,
                    message: 'Same receipt already uploaded'
                });
            }
        }



        // ================= CREATE =================

        const expense = await Expense.create({
            expense_name,
            category,
            amount,
            expense_date,
            vendor,
            payment_method,
            receipt,
            status: status || 'pending'
        });



        // ================= RESPONSE =================

        return res.status(201).json({
            success: true,
            message: 'Expense created successfully',
            expense
        });

    } catch (error) {

        console.log('Create Expense Error:', error);



        // error case mein uploaded file delete

        if (req.file) {

            const filePath = path.join(
                'uploads',
                req.file.filename
            );

            if (fs.existsSync(filePath)) {
                fs.unlinkSync(filePath);
            }
        }



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

    }
};

// ================= GET ALL EXPENSES =================

export const getExpenses = async (req, res) => {
    try {

        const {
            category,
            status,
            search
        } = req.query;



        const where = {};



        // ================= FILTER =================

        if (category) {
            where.category = category;
        }

        if (status) {
            where.status = status;
        }



        // ================= SEARCH =================

        if (search) {

            where[Op.or] = [

                {
                    expense_name: {
                        [Op.like]: `%${search}%`
                    }
                },

                {
                    vendor: {
                        [Op.like]: `%${search}%`
                    }
                }

            ];

        }



        // ================= GET DATA =================

        const expenses = await Expense.findAll({
            where,
            order: [
                ['expense_date', 'DESC']
            ]
        });



        // ================= RESPONSE =================

        return res.status(200).json({
            success: true,
            total: expenses.length,
            expenses
        });

    } catch (error) {

        console.log('Get Expenses Error:', error);

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

    }
};




// ================= GET SINGLE EXPENSE =================

export const getExpenseById = async (req, res) => {
    try {

        const { id } = req.params;



        const expense = await Expense.findByPk(id);



        if (!expense) {
            return res.status(404).json({
                success: false,
                message: 'Expense not found'
            });
        }



        return res.status(200).json({
            success: true,
            expense
        });

    } catch (error) {

        console.log('Get Expense By ID Error:', error);

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

    }
};


// ================= UPDATE EXPENSE =================

export const updateExpense = async (req, res) => {
    try {

        const { id } = req.params;



        const expense = await Expense.findByPk(id);



        if (!expense) {
            return res.status(404).json({
                success: false,
                message: 'Expense not found'
            });
        }
        // ================= IMAGE UPDATE =================

        if (req.file) {
            req.body.receipt = req.file.filename;
        }
        // ================= CATEGORY VALIDATION =================

        if (
            req.body.category &&
            !allowedCategories.includes(req.body.category)
        ) {
            return res.status(400).json({
                success: false,
                message: `Category must be one of: ${allowedCategories.join(', ')}`
            });
        }
        // ================= STATUS VALIDATION =================

        if (
            req.body.status &&
            !allowedStatuses.includes(req.body.status)
        ) {
            return res.status(400).json({
                success: false,
                message: `Status must be one of: ${allowedStatuses.join(', ')}`
            });
        }
        // ================= UPDATE =================

        await expense.update(req.body);
        // ================= RESPONSE =================

        return res.status(200).json({
            success: true,
            message: 'Expense updated successfully',
            expense
        });

    } catch (error) {

        console.log('Update Expense Error:', error);

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

    }
};
// ================= DELETE EXPENSE =================

export const deleteExpense = async (req, res) => {
    try {

        const { id } = req.params;



        const expense = await Expense.findByPk(id);



        if (!expense) {
            return res.status(404).json({
                success: false,
                message: 'Expense not found'
            });
        }
        await expense.destroy();
        return res.status(200).json({
            success: true,
            message: 'Expense deleted successfully'
        });

    } catch (error) {

        console.log('Delete Expense Error:', error);

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

    }
};
// ================= EXPENSE DASHBOARD STATS =================

export const getExpenseStats = async (req, res) => {
    try {

        // ================= CURRENT MONTH =================

        const startOfMonth = new Date(
            new Date().getFullYear(),
            new Date().getMonth(),
            1
        );

        const endOfMonth = new Date(
            new Date().getFullYear(),
            new Date().getMonth() + 1,
            0
        );
        // ================= TOTAL MONTHLY EXPENSES =================

        const totalMonthlyExpenses = await Expense.sum('amount', {
            where: {
                expense_date: {
                    [Op.between]: [startOfMonth, endOfMonth]
                }
            }
        });
        // ================= TOTAL BUDGET =================

        const totalBudget = 20000;

        const budgetRemaining =
            totalBudget - (totalMonthlyExpenses || 0);

        // ================= PENDING EXPENSES =================

        const pendingExpenses = await Expense.sum('amount', {
            where: {
                status: 'pending'
            }
        });

        const pendingRequests = await Expense.count({
            where: {
                status: 'pending'
            }
        });
        // ================= AVERAGE DAILY SPEND =================

        const totalDays = new Date().getDate();

        const averageDailySpend =
            (totalMonthlyExpenses || 0) / totalDays;
        // ================= RESPONSE =================

        return res.status(200).json({
            success: true,

            stats: {

                totalMonthlyExpenses:
                    Number(totalMonthlyExpenses || 0).toFixed(2),

                budgetRemaining:
                    Number(budgetRemaining || 0).toFixed(2),

                pendingExpenses:
                    Number(pendingExpenses || 0).toFixed(2),

                pendingRequests,

                averageDailySpend:
                    Number(averageDailySpend || 0).toFixed(2)

            }
        });

    } catch (error) {

        console.log('Expense Stats Error:', error);

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

    }
};

// ================= EXPENSE TRENDS =================

export const getExpenseTrends = async (req, res) => {
    try {
        const monthLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
        const currentYear = new Date().getFullYear();
        const startOfYear = new Date(currentYear, 0, 1);
        const endOfYear = new Date(currentYear, 11, 31);

        const trends = monthLabels.map((label, month) => ({
            label,
            month,
            year: currentYear,
            amount: 0
        }));

        const expenses = await Expense.findAll({
            where: {
                expense_date: {
                    [Op.between]: [startOfYear, endOfYear]
                }
            },
            attributes: ['amount', 'expense_date']
        });

        expenses.forEach((expense) => {
            const date = new Date(expense.expense_date);
            if (Number.isNaN(date.getTime()) || date.getFullYear() !== currentYear) return;

            const bucket = trends[date.getMonth()];
            if (bucket) {
                bucket.amount += Number(expense.amount || 0);
            }
        });

        return res.status(200).json({
            success: true,
            trends
        });
    } catch (error) {
        console.log('Expense Trends Error:', error);

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