import { Invoice } from '../models/index.js';

import fs from "fs";

export const createInvoice = async (req, res) => {
    console.log('create invoice route hit');
    console.log('body:', req.body);
    console.log('file:', req.file);

    try {
        const {
            invoice_number,
            client_name,
            client_email,
            date,
            address,
            phone,
            gst_in,
            sac_code,
            gst_percent,
            status,
            total_amount,
            items,
            description,
        } = req.body;

        const owner_signature = req.file
            ? `/uploads/${req.file.filename}`
            : null;

        let parsedItems = [];
        if (items) {
            parsedItems = typeof items === 'string' ? JSON.parse(items) : items;
            if (!Array.isArray(parsedItems)) {
                parsedItems = [];
            }
        }

        const normalizedItems = parsedItems.map((item) => ({
            desc: item.desc || item.description || '',
            sacCode: item.sacCode || item.sac_code || '',
            amount: Number(item.amount ?? item.rate ?? 0),
        }));

        const normalizedDescription = description
            ? String(description)
            : normalizedItems
                  .map((item) => `${item.desc} (${item.sacCode || 'SAC'}) - ₹${item.amount.toFixed(2)}`)
                  .join(', ');

        const normalizedSacCode = sac_code
            ? String(sac_code)
            : [...new Set(normalizedItems.map((item) => item.sacCode).filter(Boolean))].join(', ');

        const normalizedAmount = Number(total_amount ?? normalizedItems.reduce((sum, item) => sum + item.amount, 0)).toFixed(2);
        const normalizedAmountDetails = normalizedItems.map((item) => item.amount.toFixed(2)).join(', ');

        // validation
        if (!invoice_number || !client_name || !normalizedAmount || !owner_signature) {

            // uploaded file delete
            if (req.file) {
                fs.unlinkSync(req.file.path);
            }

            return res.status(400).json({
                success: false,
                message: 'Invoice number, client name, total amount, and owner signature are required'
            });
        }

        // duplicate invoice check
        const existing = await Invoice.findOne({
            where: { invoice_number }
        });

        if (existing) {

            // duplicate case => delete uploaded image
            if (req.file) {
                fs.unlinkSync(req.file.path);
            }

            return res.status(409).json({
                success: false,
                message: 'Invoice number already exists'
            });
        }

        // create invoice
        const invoice = await Invoice.create({
            invoice_number,
            client_name,
            client_email,
            date,
            address,
            phone,
            gst_in,
            sac_code: normalizedSacCode,
            gst_percent,
            total_amount: normalizedAmount,
            amount_details: normalizedAmountDetails,
            status: status || 'pending',
            owner_signature,
            items: normalizedItems,
            description: normalizedDescription,
        });

        res.status(201).json({
            success: true,
            message: 'Invoice created successfully',
            invoice
        });

    } catch (error) {

        console.log(error);

        // any error => delete uploaded image
        if (req.file) {
            fs.unlinkSync(req.file.path);
        }

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

export const getInvoices = async (req, res) => {
    try {
        const invoices = await Invoice.findAll({ order: [['created_at', 'DESC']] });
        res.status(200).json({ success: true, invoices });
    } catch (error) {
        console.log(error);
        res.status(500).json({ success: false, message: 'Internal server error' });
    }
};

export const getInvoiceById = async (req, res) => {
    try {
        const { id } = req.params;
        const invoice = await Invoice.findByPk(id);

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

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

export const updateInvoice = async (req, res) => {
    console.log("update invoice route hit");
    console.log("body:", req.body);
    console.log("file:", req.file);

    try {

        const { id } = req.params;

        const {
            invoice_number,
            client_name,
            client_email,
            date,
            address,
            phone,
            gst_in,
            sac_code,
            gst_percent,
            status,
            total_amount,
            items,
            description,
        } = req.body;

        // find invoice
        const invoice = await Invoice.findByPk(id);

        if (!invoice) {

            // delete uploaded file if invoice not found
            if (req.file) {
                fs.unlinkSync(req.file.path);
            }

            return res.status(404).json({
                success: false,
                message: "Invoice not found"
            });
        }

        // duplicate invoice number check
        if (invoice_number) {

            const existingInvoice = await Invoice.findOne({
                where: { invoice_number }
            });

            // another invoice already using same invoice number
            if (existingInvoice && existingInvoice.id != id) {

                if (req.file) {
                    fs.unlinkSync(req.file.path);
                }

                return res.status(409).json({
                    success: false,
                    message: "Invoice number already exists"
                });
            }
        }

        // old signature
        let owner_signature = invoice.owner_signature;

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

            // delete old image
            if (invoice.owner_signature) {

                const oldPath = `.${invoice.owner_signature}`;

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

            owner_signature = `/uploads/${req.file.filename}`;
        }

        let parsedItems = [];
        if (items) {
            parsedItems = typeof items === 'string' ? JSON.parse(items) : items;
            if (!Array.isArray(parsedItems)) {
                parsedItems = [];
            }
        }

        const normalizedItemsForUpdate = parsedItems.map((item) => ({
            desc: item.desc || item.description || '',
            sacCode: item.sacCode || item.sac_code || '',
            amount: Number(item.amount ?? item.rate ?? 0),
        }));

        const normalizedAmountDetailsForUpdate = normalizedItemsForUpdate.map((item) => item.amount.toFixed(2)).join(', ');
        const normalizedSacCodeForUpdate = sac_code
            ? String(sac_code)
            : [...new Set(normalizedItemsForUpdate.map((item) => item.sacCode).filter(Boolean))].join(', ');
        const normalizedTotalAmountForUpdate = Number(total_amount ?? normalizedItemsForUpdate.reduce((sum, item) => sum + item.amount, 0)).toFixed(2);

        // update invoice
        await invoice.update({
            invoice_number,
            client_name,
            client_email,
            date,
            address,
            phone,
            gst_in,
            sac_code: normalizedSacCodeForUpdate,
            gst_percent,
            total_amount: normalizedTotalAmountForUpdate,
            amount_details: normalizedAmountDetailsForUpdate,
            status,
            owner_signature,
            items: normalizedItemsForUpdate,
            description,
        });

        res.status(200).json({
            success: true,
            message: "Invoice updated successfully",
            invoice
        });

    } catch (error) {

        console.log(error);

        // delete newly uploaded file if error occurs
        if (req.file) {
            fs.unlinkSync(req.file.path);
        }

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

export const deleteInvoice = async (req, res) => {
    try {
        const { id } = req.params;
        const invoice = await Invoice.findByPk(id);

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

        await invoice.destroy();
        res.status(200).json({ success: true, message: 'Invoice deleted successfully' });
    } catch (error) {
        console.log(error);
        res.status(500).json({ success: false, message: 'Internal server error' });
    }
};

export const getClientList = async (req, res) => {
    try {
        const invoices = await Invoice.findAll({
            attributes: ['client_name', 'client_email'],
            order: [['created_at', 'DESC']],
        });

        const seen = new Map();
        invoices.forEach((inv) => {
            const name = inv.client_name?.trim();
            if (name && !seen.has(name)) {
                seen.set(name, inv.client_email || '');
            }
        });

        const clients = Array.from(seen.entries()).map(([name, email]) => ({ name, email }));

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