const { Invoice, InvoiceItem, Quote, QuoteItem } = require('../models/billing');
const { Client } = require('../models/client');
const { Income, IncomeCategory } = require('../models/income');
const { logAction } = require('../utils/logger');
const { sequelize } = require('../config/db');

exports.createInvoice = async (data, userId) => {
    const transaction = await sequelize.transaction();
    try {
        const count = await Invoice.count();
        const invoiceNumber = `INV-${(count + 1).toString().padStart(4, '0')}`;

        const invoice = await Invoice.create({
            ...data,
            invoiceNumber,
            createdBy: userId,
            balanceDue: data.total,
            nextRecurringDate: (data.isRecurring && data.recurringStartDate) ? data.recurringStartDate : null
        }, { transaction });

        if (data.items && data.items.length > 0) {
            const items = data.items.map(item => ({ ...item, invoiceId: invoice.id }));
            await InvoiceItem.bulkCreate(items, { transaction });
        }

        await transaction.commit();
        await logAction(userId, 'CREATE', 'INVOICE', { id: invoice.id, number: invoiceNumber }, null);
        return invoice;
    } catch (err) {
        await transaction.rollback();
        throw err;
    }
};

exports.convertQuote = async (quoteId, userId) => {
    const transaction = await sequelize.transaction();
    try {
        const quote = await Quote.findByPk(quoteId, { include: ['items'] });
        if (!quote) throw new Error('Quote not found');
        if (quote.status === 'Accepted') throw new Error('Quote already converted');

        const count = await Invoice.count();
        const invoiceNumber = `INV-${(count + 1).toString().padStart(4, '0')}`;

        const invoice = await Invoice.create({
            clientId: quote.clientId,
            invoiceNumber,
            issueDate: new Date(),
            dueDate: new Date(Date.now() + 15 * 24 * 60 * 60 * 1000), // Default 15 days
            subtotal: quote.subtotal,
            tax: quote.tax,
            discount: quote.discount,
            total: quote.total,
            balanceDue: quote.total,
            theme: quote.theme,
            taxes: quote.taxes,
            source: 'Quote',
            quoteId: quote.id,
            createdBy: userId,
            status: 'Draft'
        }, { transaction });

        const items = quote.items.map(item => ({
            invoiceId: invoice.id,
            description: item.description,
            quantity: item.quantity,
            unitPrice: item.unitPrice,
            taxRate: item.taxRate,
            taxAmount: item.taxAmount,
            lineTotal: item.lineTotal
        }));
        await InvoiceItem.bulkCreate(items, { transaction });

        // Lock the quote
        quote.status = 'Accepted';
        await quote.save({ transaction });

        await transaction.commit();
        await logAction(userId, 'CONVERT', 'QUOTE_TO_INVOICE', { quoteId, invoiceId: invoice.id }, null);
        return invoice;
    } catch (err) {
        await transaction.rollback();
        throw err;
    }
};

exports.markPaid = async (invoiceId, userId, paymentData = {}) => {
    // Instead of manually updating, we delegate to recordPayment which handles banking & income logic
    const { recordPayment } = require('./paymentService');
    const invoice = await Invoice.findByPk(invoiceId);
    if (!invoice) throw new Error('Invoice not found');

    const amount = parseFloat(paymentData.amount) || parseFloat(invoice.balanceDue);
    if (amount <= 0) throw new Error('Invalid payment amount');

    return await recordPayment({
        invoiceId,
        amount,
        paymentMethod: paymentData.paymentMethod || 'Bank',
        bankAccountId: paymentData.bankAccountId,
        transactionReference: paymentData.transactionReference || `MANUAL-${invoice.invoiceNumber}`
    }, userId);
};

exports.getAllInvoices = async (filters = {}) => {
    const where = {};
    if (filters.clientId) where.clientId = filters.clientId;
    if (filters.status) where.status = filters.status;

    return await Invoice.findAll({
        where,
        include: [Client, 'items'],
        order: [['createdAt', 'DESC']]
    });
};

exports.getInvoiceById = async (id, clientId = null) => {
    const where = { id };
    if (clientId) where.clientId = clientId;
    return await Invoice.findOne({ where, include: [Client, 'items'] });
};

exports.updateInvoice = async (id, data, userId) => {
    const transaction = await sequelize.transaction();
    try {
        const invoice = await Invoice.findByPk(id);
        if (!invoice) throw new Error('Invoice not found');

        await invoice.update(data, { transaction });

        if (data.items) {
            await InvoiceItem.destroy({ where: { invoiceId: id }, transaction });
            const items = data.items.map(item => ({ ...item, invoiceId: id }));
            await InvoiceItem.bulkCreate(items, { transaction });
        }

        await transaction.commit();
        await logAction(userId, 'UPDATE', 'INVOICE', { id }, null);
        return invoice;
    } catch (err) {
        await transaction.rollback();
        throw err;
    }
};

exports.deleteInvoice = async (id, userId) => {
    const invoice = await Invoice.findByPk(id);
    if (!invoice) throw new Error('Invoice not found');

    await invoice.destroy();
    await logAction(userId, 'DELETE', 'INVOICE', { id }, null);
    return true;
};
