const express = require('express');
var invoiceRouter = express.Router();
const models = require('../models/index.js');
const chkLogin = require('../middleware/auth.js');
const aclCheck = require('../middleware/aclCheck.js');
const requireUserGroup = require('../middleware/requireUserGroup.js');
const validateListQuery = require('../middleware/validateListQuery.js');
var resp = require('../response.js');
// const Invoice = require('../models/invoice.js');

const validateEntityScopedListQuery = validateListQuery({ requireEntId: true });

invoiceRouter.use(chkLogin, requireUserGroup('User'));

const isSessionAdmin = (req) => {
    const acl = req?.session?.userAcl;
    if (!Array.isArray(acl)) return false;
    return acl.some((a) => a.name === 'User' && !!a?.GroupModules?.update);
};

const denyAdminInvoiceAccess = (req, res) => {
    if (!isSessionAdmin(req)) return false;
    res.json(
        resp(
            'Access Denied',
            'Admin users are not allowed to view invoices.',
            null,
            req,
            false
        )
    );
    return true;
};

invoiceRouter.post('/createinvoice', chkLogin, aclCheck("create", "Generate Invoice"), async (req, res) => {
    new models.Invoice().createInvoice(req.body).then((result) => {
        // console.log(req.body);
        if(result.errors) {
            return res.json(    
                resp(
                    "Error",
                    "Error adding Invoice data",
                    result.errors,
                    req,
                    false
                )
            )
        }
        // console.log(req.body);
        new models.Entity().updateEntity({
            id: result.biller_id, 
            last_invoice_no: (req.body.biller_last_invoice_no + 1)
        }).then((entUpdRes) => {
            if(entUpdRes.errors) {
                return res.json(
                    resp(
                        "Error",
                        "Error updating Entity data",
                        entUpdRes.errors,
                        req,
                        false
                    )
                )
            }
            return res.json(
                resp(
                    "Invoice created",
                    "Invoice saved sucessfully",
                    {result, entUpdRes},
                    req
                )
            )
        }).catch((err) => {
            return res.json(
                resp(
                    "Error",
                    "Error updating Entity data",
                    err,
                    req
                )
            )
        })
    }).catch((err) => {
        return res.json(
            resp(
                "Error",
                "Error adding Invoice data",
                err,
                req
            )
        )
    })
});

invoiceRouter.post('/generateinvoice', chkLogin, aclCheck("read", "Generate Invoice"), async (req, res) => {
    // var creatorId = req.session.userId;
    // await Invoice.create({...req.body, creatorId});
    new models.Invoice().getInvoices(req.body.template_id, req.body.biller_id).then((result) => {
        if(result.errors) {
            return res.json(
                resp(
                    "Error",
                    "Error returning Invoices",
                    result.errors,
                    req,
                    false
                )
            )
        }
        return res.json(
            resp(
                "Invoice Draft Genarated",
                `Invoice Draft generated for ${result.name}`,
                result,
                req
            )
        )
    }).catch((err) => {
        return res.json(
            resp(
                "Error",
                "Error returning Invoices",
                err,
                req
            )
        )
    })
});

invoiceRouter.post('/getinvoicelist', chkLogin, aclCheck("read", "View Invoice"), async (req, res) => {
    if (denyAdminInvoiceAccess(req, res)) return;
    new models.Invoice().getInvoiceList(req.body.ent_id).then((result) => {
        if(result.errors) {
            return res.json(
                resp(
                    "Error",
                    "Error returning Invoices",
                    result.errors,
                    req,
                    false
                )
            )
        }
        return res.json(
            resp(
                "Invoice Drafts",
                `Invoice Drafts returned for ${result.name}`,
                result,
                req
            )
        )
    }).catch((err) => {
        return res.json(
            resp(
                "Error",
                "Error returning Invoices",
                err,
                req
            )
        )
    })
});

invoiceRouter.post('/readinvoices', chkLogin, aclCheck("read", "View Invoice"), validateEntityScopedListQuery, async (req, res) => {
    if (denyAdminInvoiceAccess(req, res)) return;
    new models.Invoice().readInvoices(req.body.ent_id, req.body.col, req.body.dir, req.body.offset, req.body.limit, req.body.search).then((result) => {
        if(result.errors) {
            return res.json(
                resp(
                    "Error",
                    "Error returning Invoices",
                    result.errors,
                    req,
                    false
                )
            )
        }
        new models.Invoice().countInvoices(req.body.ent_id).then((count) => {
            return res.json(
                resp(
                    "Invoice Drafts",
                    "Invoice Drafts returned",
                    {rows: result, rowCount: count},
                    req
                )
            )
        })
    }).catch((err) => {
        return res.json(
            resp(
                "Error",
                "Error returning Invoices",
                err,
                req
            )
        )
    })
});

invoiceRouter.post('/readinvoicerow', chkLogin, aclCheck("read", "View Invoice"), async (req, res) => {
    if (denyAdminInvoiceAccess(req, res)) return;
    new models.Invoice().readInvoiceRow(req.body.id).then((result) => {
        if(result?.errors || result instanceof Error || result?.name?.endsWith('Error')) {
            return res.json(
                resp(
                    "Error",
                    "Error returning Invoices",
                    result.errors || result,
                    req,
                    false
                )
            )
        }
        return res.json(
            resp(
                "Invoice Loaded",
                `Invoice ${result.name} generated on ${result.createdAt}`,
                result,
                req
            )
        )
    }).catch((err) => {
        return res.json(
            resp(
                "Error",
                "Error returning Invoices",
                err,
                req
            )
        )
    })
});

invoiceRouter.post('/updateinvoice', chkLogin, aclCheck("update", "View Invoice"), async (req, res) => {
    if (denyAdminInvoiceAccess(req, res)) return;
    const { id, ...data } = req.body;
    if (!id) {
        return res.status(400).json(resp("Error", "Invoice ID is required", null, req, false));
    }
    try {
        // 1. Read current invoice state (becomes og_data in the change log)
        const currentInvoice = await new models.Invoice().readInvoiceRow(id);
        if (!currentInvoice || currentInvoice instanceof Error) {
            return res.json(resp("Error", "Invoice not found", null, req, false));
        }

        // 2. Write change log: og_data = before, new_data = incoming changes
        const changeLog = await new models.ChangeLog().createChangeLog(
            id,
            req.session.userId,
            currentInvoice,
            data
        );
        if (changeLog instanceof Error || changeLog?.errors) {
            return res.json(resp("Error", "Error saving change history", changeLog.errors || changeLog, req, false));
        }

        // 3. Apply the update, linking to the new change log entry
        const result = await new models.Invoice().updateInvoice(id, { ...data, change_id: changeLog.id });
        if (result instanceof Error || result?.errors) {
            return res.json(resp("Error", "Error updating Invoice", result.errors || result, req, false));
        }

        return res.json(resp("Invoice Updated", "Invoice updated and history saved successfully", { changeLogId: changeLog.id }, req));
    } catch (err) {
        return res.json(resp("Error", "Error updating Invoice", err, req, false));
    }
});

module.exports = invoiceRouter;