import puppeteer from 'puppeteer';
import { WorkflowRequest } from '@models/WorkflowRequest';
import { ClaimInvoice } from '@models/ClaimInvoice';
import { DealerClaimDetails } from '@models/DealerClaimDetails';
import { DealerProposalDetails } from '@models/DealerProposalDetails';
import { DealerCompletionExpense } from '@models/DealerCompletionExpense';
import { ClaimInvoiceItem } from '@models/ClaimInvoiceItem';
import { ActivityType } from '@models/ActivityType';
import { amountToWords } from '@utils/currencyUtils';
import { findDealerLocally } from './dealer.service';
import path from 'path';
import fs from 'fs';
import logger from '@utils/logger';
import dayjs from 'dayjs';

export class PdfService {
  constructor() { }

  async generateInvoicePdf(requestId: string): Promise<Buffer> {
    const browser = await puppeteer.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });

    try {
      const page = await browser.newPage();

      const request = await WorkflowRequest.findByPk(requestId);
      const invoice = await ClaimInvoice.findOne({ where: { requestId } });
      const claimDetails = await DealerClaimDetails.findOne({ where: { requestId } });
      const proposalDetails = await DealerProposalDetails.findOne({ where: { requestId } });
      const completionExpenses = await DealerCompletionExpense.findAll({
        where: { requestId },
        order: [['createdAt', 'ASC']]
      });
      const invoiceItems = await ClaimInvoiceItem.findAll({
        where: { requestId },
        order: [['slNo', 'ASC']]
      });
      const dealer = await findDealerLocally(claimDetails?.dealerCode, claimDetails?.dealerEmail);

      // Resolve taxationType
      let taxationType = 'GST';
      if (claimDetails?.activityType) {
        const activity = await ActivityType.findOne({ where: { title: claimDetails?.activityType } });
        taxationType = activity?.taxationType || (claimDetails.activityType.toLowerCase().includes('non') ? 'Non GST' : 'GST');
      }

      if (!request || !invoice) {
        throw new Error('Request or Invoice not found');
      }

      const htmlContent = this.getInvoiceHtmlTemplate({
        request,
        invoice,
        claimDetails,
        proposalDetails,
        completionExpenses,
        invoiceItems,
        dealer,
        taxationType
      });

      await page.setContent(htmlContent, { waitUntil: 'networkidle0' });

      const pdfBuffer = Buffer.from(await page.pdf({
        format: 'A4',
        printBackground: true,
        margin: { top: '20px', bottom: '20px', left: '20px', right: '20px' }
      }));

      return pdfBuffer;
    } catch (error) {
      logger.error(`[PdfService] Error generating PDF for request ${requestId}:`, error);
      throw error;
    } finally {
      await browser.close();
    }
  }

  private getInvoiceHtmlTemplate(data: any): string {
    const { request, invoice, dealer, claimDetails, completionExpenses = [], invoiceItems = [], taxationType } = data;
    const qrImage = invoice.qrImage ? `data:image/png;base64,${invoice.qrImage}` : '';
    const logoUrl = `{{LOGO_URL}}`;
    const isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';

    let tableRows = '';

    if (invoiceItems && invoiceItems.length > 0) {
      // Use persisted invoice items (matches PWC payload exactly)
      tableRows = invoiceItems.map((item: any) => `
          <tr>
            <td>${item.slNo}</td>
            <td>${item.description}</td>
            ${!isNonGst ? `<td>${item.hsnCd}</td>` : ''}
            <td>${Number(item.assAmt).toFixed(2)}</td>
            <td>0.00</td>
            <td>${item.unit}</td>
            ${!isNonGst ? `<td>${Number(item.assAmt).toFixed(2)}</td>` : ''}
            ${!isNonGst ? `
            <td>${Number(item.igstAmt) > 0 ? Number(item.gstRt).toFixed(2) : '0.00'}</td>
            <td>${Number(item.igstAmt).toFixed(2)}</td>
            <td>${Number(item.cgstAmt) > 0 ? (Number(item.gstRt) / 2).toFixed(2) : '0.00'}</td>
            <td>${Number(item.cgstAmt).toFixed(2)}</td>
            <td>${Number(item.sgstAmt) > 0 ? (Number(item.gstRt) / 2).toFixed(2) : '0.00'}</td>
            <td>${Number(item.sgstAmt).toFixed(2)}</td>
            ` : ''}
            <td>${Number(isNonGst ? item.assAmt : item.totItemVal).toFixed(2)}</td>
          </tr>
        `).join('');
    } else if (completionExpenses.length > 0) {
      // Group expenses by HSN/SAC and GST Rate for clubbed display
      const grouped: Record<string, any> = {};
      completionExpenses.forEach((item: any) => {
        const hsn = item.hsnCode || 'N/A';
        const rate = Number(item.gstRate || 0);
        const key = isNonGst ? 'NON_GST' : `${hsn}_${rate}`;

        if (!grouped[key]) {
          grouped[key] = {
            hsn,
            rate,
            description: item.description || 'Expense',
            amount: 0,
            igstRate: item.igstRate || 0,
            igstAmt: 0,
            cgstRate: item.cgstRate || 0,
            cgstAmt: 0,
            sgstRate: item.sgstRate || 0,
            sgstAmt: 0,
            totalAmt: 0
          };
        }
        const qty = Number(item.quantity || 1);
        grouped[key].amount += Number(item.amount || 0) * qty;
        grouped[key].igstAmt += Number(item.igstAmt || 0);
        grouped[key].cgstAmt += Number(item.cgstAmt || 0);
        grouped[key].sgstAmt += Number(item.sgstAmt || 0);
        grouped[key].totalAmt += Number(item.totalAmt || 0);
      });

      tableRows = Object.values(grouped).map((item: any) => `
          <tr>
            <td>EXPENSE</td>
            <td>${item.description}</td>
            ${!isNonGst ? `<td>${item.hsn}</td>` : ''}
            <td>${Number(item.amount).toFixed(2)}</td>
            <td>0.00</td>
            <td>EA</td>
            ${!isNonGst ? `<td>${Number(item.amount).toFixed(2)}</td>` : ''}
            ${!isNonGst ? `
            <td>${Number(item.igstRate || 0).toFixed(2)}</td>
            <td>${Number(item.igstAmt || 0).toFixed(2)}</td>
            <td>${Number(item.cgstRate || 0).toFixed(2)}</td>
            <td>${Number(item.cgstAmt || 0).toFixed(2)}</td>
            <td>${Number(item.sgstRate || 0).toFixed(2)}</td>
            <td>${Number(item.sgstAmt || 0).toFixed(2)}</td>
            ` : ''}
            <td>${Number(isNonGst ? item.amount : item.totalAmt).toFixed(2)}</td>
          </tr>
        `).join('');
    } else {
      tableRows = `
          <tr>
            <td>CLAIM</td>
            <td>${request.title || 'Warranty Claim'}</td>
            ${!isNonGst ? '<td>998881</td>' : ''}
            <td>${Number(invoice.taxableValue || invoice.amount || 0).toFixed(2)}</td>
            <td>0.00</td>
            <td>EA</td>
            ${!isNonGst ? `<td>${Number(invoice.taxableValue || invoice.amount || 0).toFixed(2)}</td>` : ''}
            ${!isNonGst ? `
            <td>${invoice.igstTotal > 0 ? (Number(invoice.igstTotal) / Number(invoice.taxableValue || invoice.amount || 1) * 100).toFixed(2) : '0.00'}</td>
            <td>${Number(invoice.igstTotal || 0).toFixed(2)}</td>
            <td>${invoice.cgstTotal > 0 ? (Number(invoice.cgstTotal) / Number(invoice.taxableValue || invoice.amount || 1) * 100).toFixed(2) : '0.00'}</td>
            <td>${Number(invoice.cgstTotal || 0).toFixed(2)}</td>
            <td>${invoice.sgstTotal > 0 ? (Number(invoice.sgstTotal) / Number(invoice.taxableValue || invoice.amount || 1) * 100).toFixed(2) : '0.00'}</td>
            <td>${Number(invoice.sgstTotal || 0).toFixed(2)}</td>
            ` : ''}
            <td>${Number(isNonGst ? (invoice.taxableValue || invoice.amount) : invoice.amount || 0).toFixed(2)}</td>
          </tr>
        `;
    }

    let totalTaxable = 0;
    let totalTax = 0;
    let grandTotal = 0;

    if (invoiceItems && invoiceItems.length > 0) {
      invoiceItems.forEach((item: any) => {
        totalTaxable += Number(item.assAmt || 0);
        if (!isNonGst) {
          totalTax += Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0);
          grandTotal += Number(item.totItemVal || 0);
        } else {
          grandTotal += Number(item.assAmt || 0);
        }
      });
    } else if (completionExpenses.length > 0) {
      completionExpenses.forEach((item: any) => {
        const qty = Number(item.quantity || 1);
        const baseAmt = Number(item.amount || 0) * qty;
        totalTaxable += baseAmt;
        if (!isNonGst) {
          const taxAmt = Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0);
          totalTax += taxAmt;
          grandTotal += (baseAmt + taxAmt);
        } else {
          grandTotal += baseAmt;
        }
      });
    } else {
      totalTaxable = Number(invoice.taxableValue || invoice.amount || 0);
      if (!isNonGst) {
        totalTax = Number(invoice.igstTotal || 0) + Number(invoice.cgstTotal || 0) + Number(invoice.sgstTotal || 0);
        grandTotal = Number(invoice.amount || 0);
      } else {
        grandTotal = totalTaxable;
      }
    }

    const totalValueInWords = amountToWords(grandTotal);
    const totalTaxInWords = amountToWords(totalTax);

    return `
      <!DOCTYPE html>
      <html>
      <head>
        <style>
          body { font-family: Arial, sans-serif; margin: 0; padding: 20px; color: #333; }
          .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px; }
          .logo { height: 40px; }
          .qr-code { width: 150px; height: 150px; }
          .irn-details { font-size: 11px; margin-top: 10px; }
          .irn-details div { margin-bottom: 4px; }
          .title { text-align: center; font-size: 24px; font-weight: bold; margin: 30px 0; border-top: 1px solid #ccc; padding-top: 20px; }
          .info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-bottom: 30px; font-size: 12px; }
          .info-section h3 { font-size: 14px; margin-bottom: 10px; }
          .info-row { display: flex; margin-bottom: 5px; }
          .info-label { width: 120px; font-weight: bold; }
          .info-value { flex: 1; }
          table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 10px; }
          th, td { border: 1px solid #333; padding: 6px; text-align: left; }
          th { background-color: #f2f2f2; }
          .totals { margin-top: 20px; width: 300px; margin-left: auto; font-size: 12px; }
          .totals-row { display: flex; justify-content: space-between; padding: 5px 0; }
          .totals-row.grand-total { border-top: 2px solid #333; font-weight: bold; margin-top: 10px; }
          .words { margin-top: 30px; font-size: 11px; font-style: italic; }
          .footer { margin-top: 60px; text-align: right; font-size: 12px; }
          .signature { margin-top: 40px; border-top: 1px solid #333; width: 200px; margin-left: auto; text-align: center; padding-top: 5px; }
        </style>
      </head>
      <body>
        <div class="header">
          <div>
            <img src="${logoUrl}" class="logo" />
            <div class="irn-details">
              ${invoice.irn ? `<div><strong>IRN No :</strong> ${invoice.irn}</div>` : ''}
              ${invoice.ackNo ? `<div><strong>Ack No :</strong> ${invoice.ackNo}</div>` : ''}
              ${invoice.ackDate ? `<div><strong>Ack Date & Time :</strong> ${dayjs(invoice.ackDate).format('YYYY-MM-DD HH:mm:ss')}</div>` : ''}
            </div>
          </div>
          ${qrImage ? `<img src="${qrImage}" class="qr-code" />` : ''}
        </div>

        <div class="title">${isNonGst ? 'CLAIM INVOICE' : 'CLAIM TAX INVOICE'}</div>

        <div class="info-grid">
          <div class="info-section">
            <div class="info-row"><div class="info-label">Customer Name</div><div class="info-value">Royal Enfield</div></div>
            <div class="info-row"><div class="info-label">Customer GSTIN</div><div class="info-value">33AAACE3882D1ZZ</div></div>
            <div class="info-row"><div class="info-label">Customer Address</div><div class="info-value">State Highway 48, Vallam Industrial Corridor, Vallakottai Chennai, Tamil Nadu - 631604</div></div>
          </div>
          <div class="info-section">
            <div class="info-row"><div class="info-label">Dealer</div><div class="info-value">${dealer?.dealerName || claimDetails?.dealerName || 'N/A'}</div></div>
            <div class="info-row"><div class="info-label">Store</div><div class="info-value">${dealer?.dealerName || claimDetails?.dealerName || 'N/A'}</div></div>
            <div class="info-row"><div class="info-label">Supplier GSTIN</div><div class="info-value">${dealer?.gstin || 'N/A'}</div></div>
            <br/>
            <div class="info-row"><div class="info-label">POS</div><div class="info-value">${invoice.placeOfSupply || dealer?.state || 'Test State'}</div></div>
            <div class="info-row"><div class="info-label">Claim Request Number</div><div class="info-value">${request.requestNumber || 'N/A'}</div></div>
            <div class="info-row"><div class="info-label">Claim Invoice No.</div><div class="info-value">${invoice.invoiceNumber || 'N/A'}</div></div>
            <div class="info-row"><div class="info-label">Claim Invoice Date</div><div class="info-value">${invoice.invoiceDate ? dayjs(invoice.invoiceDate).format('DD-MM-YYYY') : dayjs().format('DD-MM-YYYY')}</div></div>
            <div class="info-row"><div class="info-label">Last Approval Date</div><div class="info-value">${invoice.generatedAt ? dayjs(invoice.generatedAt).format('DD-MM-YYYY') : dayjs().format('DD-MM-YYYY')}</div></div>
          </div>
        </div>

        <table>
          <thead>
            <tr>
              <th>Part</th>
              <th>Description</th>
              ${!isNonGst ? '<th>HSN/SAC</th>' : ''}
              <th>${isNonGst ? 'Amount' : 'Base Amount'}</th>
              <th>Disc</th>
              <th>UOM</th>
              ${!isNonGst ? '<th>Taxable Value</th>' : ''}
              ${!isNonGst ? `
              <th>IGST %</th>
              <th>IGST</th>
              <th>CGST %</th>
              <th>CGST</th>
              <th>SGST %</th>
              <th>SGST</th>
              ` : ''}
              <th>Total</th>
            </tr>
          </thead>
          <tbody>
            ${tableRows}
          </tbody>
        </table>

        <div class="totals">
          <div class="totals-row"><span>${isNonGst ? 'TOTAL AMOUNT' : 'TAXABLE TOTAL'}:</span><span>${totalTaxable.toFixed(2)}</span></div>
          ${!isNonGst ? `<div class="totals-row"><span>TOTAL TAX:</span><span>${totalTax.toFixed(2)}</span></div>` : ''}
          <div class="totals-row grand-total"><span>GRAND TOTAL:</span><span>${grandTotal.toFixed(2)}</span></div>
        </div>

        <div class="words">
          <div><strong>TOTAL VALUE IN WORDS:</strong> Rupees ${totalValueInWords}</div>
          ${!isNonGst ? `<div><strong>TOTAL TAX IN WORDS:</strong> Rupees ${totalTaxInWords}</div>` : ''}
        </div>

        <div class="footer">
          <p>For ${dealer?.name || 'Authorised Dealer'}</p>
          <div class="signature">Authorised signatory</div>
        </div>
      </body>
      </html>
    `;
  }
}

export const pdfService = new PdfService();
