
import type { Request, Response } from "express";
import { ReportService } from "../services/ReportService.js";
import { generatePurchaseExcel, mapPurchaseToExportRow } from "../utils/excel/PurchaseExcelExport.js";
import { generateLotwiseStockExcel } from "../utils/excel/LotwiseStockExcelExport.js";
import { generateSaleExcel, mapSaleToExportRow } from "../utils/excel/SaleExcelExport.js";
import { generateVegWiseSaleExcel, mapVegWiseSaleToExportRow } from "../utils/excel/VegWiseSaleExcelExport.js";
import { generateCustomerLedgerExcel } from "../utils/excel/CustomerLedgerExcelExport.js";
import { generateSupplierLedgerExcel } from "../utils/excel/SupplierLedgerExcelExport.js";
import { generateArrivalReportExcel, mapArrivalToExportRow } from "../utils/excel/ArrivalReportExcelExport.js";
import { generateArrivalSettlementExcel, mapArrivalSettlementToExportRow } from "../utils/excel/ArrivalSettlementExcelExport.js";
import { PurchaseReportPdf } from "../utils/pdf/PurchaseReportPdf.js";
import { CustomerLedgerPdf } from "../utils/pdf/CustomerLedgerPdf.js";
import { SupplierLedgerPdf } from "../utils/pdf/SupplierLedgerPdf.js";
import { StockReportPdf } from "../utils/pdf/StockReportPdf.js";
import { WholeSalesListPdf } from "../utils/pdf/WholeSalesListPdf.js";
import { VegWiseSalesPdf } from "../utils/pdf/VegWiseSalesPdf.js";
import { WholesaleDailySummaryPdf } from "../utils/pdf/WholesaleDailySummaryPdf.js";
import { RetailDailySummaryPdf } from "../utils/pdf/RetailDailySummaryPdf.js";
import { ArrivalReportPdf } from "../utils/pdf/ArrivalReportPdf.js";
import { ArrivalSettlementReportPdf } from "../utils/pdf/ArrivalSettlementReportPdf.js";
import { generateLotWiseSaleExcel, mapLotWiseSaleToExportRow } from "../utils/excel/LotWiseSaleExcelExport.js";
import { LotWiseSalesPdf } from "../utils/pdf/LotWiseSalesPdf.js";


export class ReportController {

  constructor(private readonly reportService = new ReportService()) { }

  getAll = async (req: Request, res: Response): Promise<void> => {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 10;
      const search = req.query.search as string;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string;
      const dateTo = req.query.dateTo as string;

      const result = await this.reportService.getPurchaseData(
        page, limit, search, supplierId, vegetableId, dateFrom, dateTo
      );
      res.status(200).json({ message: "Purchases fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch purchases";
      res.status(500).json({ message });
    }
  };
  exportPurchases = async (req: Request, res: Response): Promise<void> => {
    try {
      const search = req.query.search as string | undefined;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data } = await this.reportService.getExportData(
        search, supplierId, vegetableId, dateFrom, dateTo
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      const rows = data.map(mapPurchaseToExportRow);

      const dateTag = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
      await generatePurchaseExcel(rows, res, `purchase-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export purchases";
      res.status(500).json({ message });
    }
  };

  exportPurchasesPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const search = req.query.search as string | undefined;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data, outstanding_balance_sum } = await this.reportService.getExportData(
        search, supplierId, vegetableId, dateFrom, dateTo
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      let supplierName: string | undefined;
      let vegetableName: string | undefined;
      if (supplierId && data.length > 0) {
        const found = data.find((item: any) => item.supplierId === supplierId || item.supplier?.id === supplierId);
        if (found) supplierName = (found as any).supplier?.name || (found as any).supplierName;
      }
      if (vegetableId && data.length > 0) {
        const found = data.find((item: any) => item.vegetableId === vegetableId || item.vegetable?.id === vegetableId);
        if (found) vegetableName = (found as any).vegetable?.name || (found as any).vegetableName;
      }

      await PurchaseReportPdf.generate(data, res, {
        ...(search ? { search } : {}),
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo ? { dateTo } : {}),
        ...(supplierName ? { supplier: supplierName } : {}),
        ...(vegetableName ? { vegetable: vegetableName } : {}),
        outstandingBalance: Number(outstanding_balance_sum ?? 0)
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export purchases as PDF";
      res.status(500).json({ message });
    }
  };

  //Sales Report Related function

  getSalesData = async (req: Request, res: Response): Promise<void> => {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 10;
      const isWalkIn = req.query.isWalkIn === 'true' || req.query.customerId === 'walkin';
      const customerIdRaw = req.query.customerId as string | undefined;
      const customerId = (customerIdRaw && customerIdRaw !== 'walkin') ? BigInt(customerIdRaw) : undefined;
      const dateFrom = req.query.dateFrom as string;
      const dateTo = req.query.dateTo as string;

      const result = await this.reportService.getSalesData(
        page, limit, customerId, dateFrom, dateTo, isWalkIn
      );
      res.status(200).json({ message: "Sales fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch sales";
      res.status(500).json({ message });
    }
  };

  getCustomerLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const customerId = req.query.customerId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const result = await this.reportService.getCustomerLedgerData(customerId, dateFrom, dateTo);
      res.status(200).json({ message: "Customer ledger fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch customer ledger";
      res.status(500).json({ message });
    }
  };

  exportCustomerLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const customerId = req.query.customerId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data, summary } = await this.reportService.getCustomerLedgerExportData(customerId, dateFrom, dateTo);
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateCustomerLedgerExcel(data, summary, res, `customer-ledger-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export customer ledger";
      res.status(500).json({ message });
    }
  };

  exportCustomerLedgerPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const customerId = req.query.customerId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data, summary } = await this.reportService.getCustomerLedgerExportData(customerId, dateFrom, dateTo);
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      await CustomerLedgerPdf.generate(data, summary, res, {
        ...(customerId ? { customerId } : {}),
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo ? { dateTo } : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export customer ledger as PDF";
      res.status(500).json({ message });
    }
  };

    getCustomerLedgerMeta = async (req: Request, res: Response): Promise<void> => {
    try {
      const customers = await this.reportService.getCustomerListForLedger();
      res.status(200).json({ message: "Customer list fetched", result: { customers } });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch customers";
      res.status(500).json({ message });
    }
  };

  getSupplierLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const supplierId = req.query.supplierId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const result = await this.reportService.getSupplierLedgerData(supplierId, dateFrom, dateTo);
      res.status(200).json({ message: "Supplier ledger fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch supplier ledger";
      res.status(500).json({ message });
    }
  };

  exportSupplierLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const supplierId = req.query.supplierId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data, summary } = await this.reportService.getSupplierLedgerExportData(supplierId, dateFrom, dateTo);
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateSupplierLedgerExcel(data, summary, res, `supplier-ledger-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export supplier ledger";
      res.status(500).json({ message });
    }
  };

  exportSupplierLedgerPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const supplierId = req.query.supplierId as string | undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data, summary } = await this.reportService.getSupplierLedgerExportData(supplierId, dateFrom, dateTo);
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      await SupplierLedgerPdf.generate(data, summary, res, {
        ...(supplierId ? { supplierId } : {}),
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo ? { dateTo } : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export supplier ledger as PDF";
      res.status(500).json({ message });
    }
  };

  getSupplierLedgerMeta = async (req: Request, res: Response): Promise<void> => {
    try {
      const suppliers = await this.reportService.getSupplierListForLedger();
      res.status(200).json({ message: "Supplier list fetched", result: { suppliers } });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch suppliers";
      res.status(500).json({ message });
    }
  };

  exportSales = async (req: Request, res: Response): Promise<void> => {
    try {
      const isWalkIn = req.query.isWalkIn === 'true' || req.query.customerId === 'walkin';
      const customerIdRaw = req.query.customerId as string | undefined;
      const customerId = (customerIdRaw && customerIdRaw !== 'walkin') ? BigInt(customerIdRaw) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data } = await this.reportService.getSalesExportData(
        customerId, dateFrom, dateTo, isWalkIn
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      const rows = data.map(mapSaleToExportRow);
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateSaleExcel(rows, res, `sales-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export sales";
      res.status(500).json({ message });
    }
  };

  exportSalesPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const isWalkIn = req.query.isWalkIn === 'true' || req.query.customerId === 'walkin';
      const customerIdRaw = req.query.customerId as string | undefined;
      const customerId = (customerIdRaw && customerIdRaw !== 'walkin') ? BigInt(customerIdRaw) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;
      const search = req.query.search as string | undefined;

      const { data } = await this.reportService.getSalesExportData(
        customerId, dateFrom, dateTo, isWalkIn
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      await WholeSalesListPdf.generate(data, res, {
        ...(search ? { search } : {}),
        ...(dateFrom ? { startDate: dateFrom } : {}),
        ...(dateTo ? { endDate: dateTo } : {})
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export sales as PDF";
      res.status(500).json({ message });
    }
  };

  getVegetableWiseSales = async (req: Request, res: Response): Promise<void> => {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 10;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string;
      const dateTo = req.query.dateTo as string;
      const search = req.query.search as string;

      const result = await this.reportService.getVegetableWiseSalesData(
        page, limit, vegetableId, dateFrom, dateTo, search
      );
      res.status(200).json({ message: "Vegetable-wise sales fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch vegetable-wise sales";
      res.status(500).json({ message });
    }
  };

  exportVegetableWiseSales = async (req: Request, res: Response): Promise<void> => {
    try {
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;
      const search = req.query.search as string | undefined;

      const { data } = await this.reportService.getVegetableWiseSalesExportData(
        vegetableId, dateFrom, dateTo, search
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      const rows = data.map(mapVegWiseSaleToExportRow);
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateVegWiseSaleExcel(rows, res, `vegetable-wise-sales-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export vegetable-wise sales";
      res.status(500).json({ message });
    }
  };

  exportVegetableWiseSalesPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;
      const search = req.query.search as string | undefined;

      const { data } = await this.reportService.getVegetableWiseSalesExportData(
        vegetableId, dateFrom, dateTo, search
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      let vegetableName: string | undefined;
      if (vegetableId && data.length > 0) {
        const found = data.find((item: any) => item.purchase?.vegetable?.name);
        if (found) vegetableName = found.purchase.vegetable.name;
      }

      await VegWiseSalesPdf.generate(data, res, {
        ...(search ? { search } : {}),
        ...(dateFrom ? { startDate: dateFrom } : {}),
        ...(dateTo ? { endDate: dateTo } : {}),
        ...(vegetableName ? { vegetable: vegetableName } : {})
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export vegetable-wise sales as PDF";
      res.status(500).json({ message });
    }
  };

  // Lot-wise Sales Report Related functions
  getLotWiseSales = async (req: Request, res: Response): Promise<void> => {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 10;
      const lotNo = req.query.lotNo as string | undefined;
      const date = req.query.date as string | undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const search = req.query.search as string | undefined;

      const result = await this.reportService.getLotWiseSalesData(
        page, limit, lotNo, date, vegetableId, search
      );
      res.status(200).json({ message: "Lot-wise sales fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch lot-wise sales";
      res.status(500).json({ message });
    }
  };

  exportLotWiseSales = async (req: Request, res: Response): Promise<void> => {
    try {
      const lotNo = req.query.lotNo as string | undefined;
      const date = req.query.date as string | undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const search = req.query.search as string | undefined;

      const { data, selectedDate } = await this.reportService.getLotWiseSalesExportData(
        lotNo, date, vegetableId, search
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      const rows = data.map(mapLotWiseSaleToExportRow);
      const lotTag = lotNo ? `-${lotNo.replace(/[^a-zA-Z0-9_-]/g, "_")}` : "";
      await generateLotWiseSaleExcel(rows, res, `lot-wise-sales-report-${selectedDate}${lotTag}`, { date: selectedDate, lotNo });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export lot-wise sales";
      res.status(500).json({ message });
    }
  };

  exportLotWiseSalesPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const lotNo = req.query.lotNo as string | undefined;
      const date = req.query.date as string | undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const search = req.query.search as string | undefined;

      const { data, selectedDate } = await this.reportService.getLotWiseSalesExportData(
        lotNo, date, vegetableId, search
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      let vegetableName: string | undefined;
      if (vegetableId && data.length > 0) {
        const found = data.find((item: any) => item.purchase?.vegetable?.name);
        if (found) vegetableName = found.purchase.vegetable.name;
      }

      await LotWiseSalesPdf.generate(data, res, {
        date: selectedDate,
        lotNo,
        vegetable: vegetableName,
        search,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export lot-wise sales as PDF";
      res.status(500).json({ message });
    }
  };

  getLotWiseMeta = async (req: Request, res: Response): Promise<void> => {
    try {
      const date = req.query.date as string | undefined;
      const result = await this.reportService.getLotWiseMeta(date);
      res.status(200).json({ message: "Lot-wise meta fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch lot-wise meta";
      res.status(500).json({ message });
    }
  };


  getStockReport = async (req: Request, res: Response): Promise<void> => {
    try {
      const page = parseInt(req.query.page as string) || 1;
      const limit = parseInt(req.query.limit as string) || 10;
      const search = req.query.search as string;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string;
      const dateTo = req.query.dateTo as string;

      const result = await this.reportService.getStockReportData(
        page, limit, search, supplierId, vegetableId, dateFrom, dateTo
      );
      res.status(200).json({ message: "Stock report fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch stock report";
      res.status(500).json({ message });
    }
  };

  exportStockReport = async (req: Request, res: Response): Promise<void> => {
    try {
      const search = req.query.search as string | undefined;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data } = await this.reportService.getExportData(
        search, supplierId, vegetableId, dateFrom, dateTo
      );
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }
      const rows = data.map(mapPurchaseToExportRow);
      const dateTag = new Date().toISOString().slice(0, 10);
      await generatePurchaseExcel(rows, res, `final-stock-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export stock report";
      res.status(500).json({ message });
    }
  };

  exportLotwiseStockExcel = async (req: Request, res: Response): Promise<void> => {
    try {
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data } = await this.reportService.getExportData(
        undefined, undefined, undefined, dateFrom, dateTo
      );
      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }
      
      const groups: Record<string, any[]> = {};
      data.forEach(item => {
        const anyItem = item as any;
        
        // --- Old code ---
        // const vegName = anyItem.vegetable?.name || anyItem.vegetableName || '-';
        // if (!groups[vegName]) groups[vegName] = [];
        // groups[vegName].push(item);
        // ----------------

        // --- New code ---
        const isBagOnly = anyItem.unit !== 'KG' && Number(anyItem.quantity || 0) === 0;
        const bUnits = Number(anyItem.remainingBags || 0);
        const bWgts = isBagOnly ? 0 : Number(anyItem.remainingQuantity || 0);
        
        if (bUnits === 0 && bWgts === 0) return;

        const vegName = anyItem.vegetable?.name || anyItem.vegetableName || '-';
        if (!groups[vegName]) groups[vegName] = [];
        groups[vegName].push(item);
      });
      
      const groupedData: any[] = [];
      Object.keys(groups).sort().forEach(vegName => {
        groupedData.push({ isHeader: true, ItemName: vegName });
        
        let tAUnits = 0, tSUnits = 0, tBUnits = 0;
        let tAWgts = 0, tSWgts = 0, tBWgts = 0;
        
        groups[vegName]!.forEach((item) => {
          const isBagOnly = item.unit !== 'KG' && Number(item.quantity || 0) === 0;
          const aUnits = Number(item.bags || 0);
          const bUnits = Number(item.remainingBags || 0);
          const sUnits = aUnits - bUnits;
          
          const aWgts = isBagOnly ? 0 : Number(item.quantity || 0);
          const bWgts = isBagOnly ? 0 : Number(item.remainingQuantity || 0);
          const sWgts = isBagOnly ? 0 : (aWgts - bWgts);
          
          tAUnits += aUnits; tSUnits += sUnits; tBUnits += bUnits;
          tAWgts += aWgts; tSWgts += sWgts; tBWgts += bWgts;
          
          const arrDateObj = item.purchaseDate ? new Date(item.purchaseDate) : null;
          const arrDate = arrDateObj ? arrDateObj.toLocaleDateString("en-GB") : '-';
          
          groupedData.push({
            isHeader: false,
            ItemName: vegName,
            LotNo: item.lotNo || '-',
            ArrDate: arrDate,
            AUnits: aUnits,
            SUnits: sUnits,
            BUnits: bUnits,
            AWgts: aWgts,
            SWgts: sWgts,
            BWgts: bWgts,
            Rate: Number(item.costPerUnit || 0),
            SupName: item.supplier?.name || item.cashSupplierName || '-',
            Loc: item.supplier?.district?.name || 'TRICHY',
          });
        });
        
        groupedData.push({
          isTotal: true,
          ItemName: vegName,
          AUnits: tAUnits,
          SUnits: tSUnits,
          BUnits: tBUnits,
          AWgts: tAWgts,
          SWgts: tSWgts,
          BWgts: tBWgts,
        });
      });

      const dateTag = new Date().toISOString().slice(0, 10);
      await generateLotwiseStockExcel(groupedData, res, `lotwise-stock-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export lotwise stock report";
      res.status(500).json({ message });
    }
  };

  exportStockReportPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const search = req.query.search as string | undefined;
      const supplierId = req.query.supplierId ? BigInt(req.query.supplierId as string) : undefined;
      const vegetableId = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const { data } = await this.reportService.getStockReportExportData(
        search, supplierId, vegetableId, dateFrom, dateTo
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No data available to export" });
        return;
      }

      await StockReportPdf.generate(data, res, {
        ...(search ? { search } : {}),
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo ? { dateTo } : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export stock report as PDF";
      res.status(500).json({ message });
    }
  };

  getWholesaleDailySummary = async (req: Request, res: Response): Promise<void> => {
    try {
      const date = req.query.date as string | undefined;
      const result = await this.reportService.getWholesaleDailySummaryData(date);
      res.status(200).json({ message: "Wholesale daily summary fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch wholesale daily summary";
      res.status(500).json({ message });
    }
  };

  exportWholesaleDailySummaryPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const date = req.query.date as string | undefined;
      const data = await this.reportService.getWholesaleDailySummaryData(date);
      await WholesaleDailySummaryPdf.generate(data, res);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export wholesale daily summary PDF";
      res.status(500).json({ message });
    }
  };

  getRetailDailySummary = async (req: Request, res: Response): Promise<void> => {
    try {
      const date = req.query.date as string | undefined;
      const result = await this.reportService.getRetailDailySummaryData(date);
      res.status(200).json({ message: "Retail daily summary fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch retail daily summary";
      res.status(500).json({ message });
    }
  };

  exportRetailDailySummaryPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const date = req.query.date as string | undefined;
      const data = await this.reportService.getRetailDailySummaryData(date);
      await RetailDailySummaryPdf.generate(data, res);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export retail daily summary PDF";
      res.status(500).json({ message });
    }
  };

  // ── Arrivals Report ──────────────────────────────────────────────

  getArrivalsReport = async (req: Request, res: Response): Promise<void> => {
    try {
      const page             = parseInt(req.query.page as string) || 1;
      const limit            = parseInt(req.query.limit as string) || 10;
      const search           = req.query.search as string | undefined;
      const supplierId       = req.query.supplierId  ? BigInt(req.query.supplierId as string)  : undefined;
      const vegetableId      = req.query.vegetableId ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom         = req.query.dateFrom as string | undefined;
      const dateTo           = req.query.dateTo   as string | undefined;
      const settlementStatus = req.query.settlementStatus as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | "ALL" | undefined;

      const result = await this.reportService.getArrivalsReportData(
        page, limit, search, supplierId, vegetableId, dateFrom, dateTo, settlementStatus
      );
      res.status(200).json({ message: "Arrivals report fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch arrivals report";
      res.status(500).json({ message });
    }
  };

  exportArrivalsReportExcel = async (req: Request, res: Response): Promise<void> => {
    try {
      const search           = req.query.search        as string | undefined;
      const supplierId       = req.query.supplierId    ? BigInt(req.query.supplierId  as string) : undefined;
      const vegetableId      = req.query.vegetableId   ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom         = req.query.dateFrom      as string | undefined;
      const dateTo           = req.query.dateTo        as string | undefined;
      const settlementStatus = req.query.settlementStatus as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | "ALL" | undefined;

      const { data } = await this.reportService.getArrivalsReportExportData(
        search, supplierId, vegetableId, dateFrom, dateTo, settlementStatus
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No arrival data available to export" });
        return;
      }

      const rows = data.map(mapArrivalToExportRow);
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateArrivalReportExcel(rows, res, `arrivals-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export arrivals report";
      res.status(500).json({ message });
    }
  };

  exportArrivalsReportPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const search           = req.query.search        as string | undefined;
      const supplierId       = req.query.supplierId    ? BigInt(req.query.supplierId  as string) : undefined;
      const vegetableId      = req.query.vegetableId   ? BigInt(req.query.vegetableId as string) : undefined;
      const dateFrom         = req.query.dateFrom      as string | undefined;
      const dateTo           = req.query.dateTo        as string | undefined;
      const settlementStatus = req.query.settlementStatus as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | "ALL" | undefined;

      const { data } = await this.reportService.getArrivalsReportExportData(
        search, supplierId, vegetableId, dateFrom, dateTo, settlementStatus
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No arrival data available to export" });
        return;
      }

      let supplierName: string | undefined;
      let vegetableName: string | undefined;
      if (supplierId && data.length > 0) {
        const found = data.find((item: any) => item.supplier?.id === supplierId || item.supplierId === supplierId);
        if (found) supplierName = (found as any).supplier?.name ?? (found as any).cashSupplierName;
      }
      if (vegetableId && data.length > 0) {
        const found = data.find((item: any) => item.vegetable?.id === vegetableId || item.vegetableId === vegetableId);
        if (found) vegetableName = (found as any).vegetable?.name;
      }

      await ArrivalReportPdf.generate(data, res, {
        ...(search           ? { search }           : {}),
        ...(dateFrom         ? { dateFrom }         : {}),
        ...(dateTo           ? { dateTo }           : {}),
        ...(supplierName     ? { supplier: supplierName }   : {}),
        ...(vegetableName    ? { vegetable: vegetableName } : {}),
        ...(settlementStatus ? { settlementStatus } : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export arrivals report as PDF";
      res.status(500).json({ message });
    }
  };

  // ── Arrival Settlements Report ───────────────────────────────────

  getArrivalSettlementsReport = async (req: Request, res: Response): Promise<void> => {
    try {
      const page     = parseInt(req.query.page  as string) || 1;
      const limit    = parseInt(req.query.limit as string) || 10;
      const search   = req.query.search   as string | undefined;
      const dateFrom = req.query.dateFrom  as string | undefined;
      const dateTo   = req.query.dateTo    as string | undefined;
      const status   = req.query.status    as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | undefined;

      const result = await this.reportService.getArrivalSettlementsReportData(
        page, limit, search, dateFrom, dateTo, status
      );
      res.status(200).json({ message: "Arrival settlements report fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch arrival settlements report";
      res.status(500).json({ message });
    }
  };

  exportArrivalSettlementsExcel = async (req: Request, res: Response): Promise<void> => {
    try {
      const search   = req.query.search   as string | undefined;
      const dateFrom = req.query.dateFrom  as string | undefined;
      const dateTo   = req.query.dateTo    as string | undefined;
      const status   = req.query.status    as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | undefined;

      const { data } = await this.reportService.getArrivalSettlementsReportExportData(
        search, dateFrom, dateTo, status
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No settlement data available to export" });
        return;
      }

      const rows = data.map(mapArrivalSettlementToExportRow);
      const dateTag = new Date().toISOString().slice(0, 10);
      await generateArrivalSettlementExcel(rows, res, `arrival-settlements-report-${dateTag}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export arrival settlements report";
      res.status(500).json({ message });
    }
  };

  exportArrivalSettlementsPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const search   = req.query.search   as string | undefined;
      const dateFrom = req.query.dateFrom  as string | undefined;
      const dateTo   = req.query.dateTo    as string | undefined;
      const status   = req.query.status    as "UNSETTLED" | "PARTIALLY_SETTLED" | "SETTLED" | undefined;

      const { data } = await this.reportService.getArrivalSettlementsReportExportData(
        search, dateFrom, dateTo, status
      );

      if (!data || data.length === 0) {
        res.status(400).json({ message: "No settlement data available to export" });
        return;
      }

      await ArrivalSettlementReportPdf.generate(data, res, {
        ...(search   ? { search }   : {}),
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo   ? { dateTo }   : {}),
        ...(status   ? { status }   : {}),
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export arrival settlements report as PDF";
      res.status(500).json({ message });
    }
  };

  // ── Walk-In Ledger ───────────────────────────────────────────────

  getWalkInLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;

      const result = await this.reportService.getWalkInLedgerData(dateFrom, dateTo);
      res.status(200).json({ message: "Walk-in ledger fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch walk-in ledger";
      res.status(500).json({ message });
    }
  };

  // ── Patti Settlement Ledger ───────────────────────────────────────

  getPattiLedger = async (req: Request, res: Response): Promise<void> => {
    try {
      const dateFrom = req.query.dateFrom as string | undefined;
      const dateTo = req.query.dateTo as string | undefined;
      const supplierId = req.query.supplierId as string | undefined;
      const status = req.query.status as any;
      const search = req.query.search as string | undefined;

      const result = await this.reportService.getPattiLedgerData(dateFrom, dateTo, supplierId, status, search);
      res.status(200).json({ message: "Patti ledger fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch patti ledger";
      res.status(500).json({ message });
    }
  };
}
