import type { Request, Response } from "express";
import { FastBillingService } from "../services/FastBillingService.js";
import { z } from "zod";

const fastBillingItemSchema = z.object({
  vegetableName: z.string().trim().min(1, "Vegetable is required"),
  unit: z.string().optional(),
  quantity: z.number().nullable().optional(),
  rateType: z.string().nullable().optional(),
  numberOfBoxes: z.number().nullable().optional(),
  numberOfThaar: z.number().nullable().optional(),
  numberOfPieces: z.number().nullable().optional(),
  ratePerUnit: z.number().nonnegative("Rate cannot be negative"),
  extraCharges: z.number().nonnegative("Extra charges cannot be negative").nullable().optional(),
  totalAmount: z.number().nonnegative("Total amount cannot be negative").optional(),
  id: z.any().optional(),
  fastBillingId: z.any().optional()
});

const fastBillingSchema = z.object({
  customerName: z.string().trim().min(1, "Customer Name is required"),
  billDate: z.string().min(1, "Bill Date is required"),
  items: z.array(fastBillingItemSchema).min(1, "At least one item is required"),
  remarks: z.string().optional().nullable(),
  totalAmount: z.number().optional()
});

const formatItem = (item: any) => ({
  ...item,
  id: item.id.toString(),
  fastBillingId: item.fastBillingId.toString(),
  quantity: item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined,
  ratePerUnit: Number(item.ratePerUnit),
  extraCharges: item.extraCharges !== null && item.extraCharges !== undefined ? Number(item.extraCharges) : 0,
  numberOfBoxes: item.numberOfBoxes !== null && item.numberOfBoxes !== undefined ? Number(item.numberOfBoxes) : undefined,
  numberOfThaar: item.numberOfThaar !== null && item.numberOfThaar !== undefined ? Number(item.numberOfThaar) : undefined,
  numberOfPieces: item.numberOfPieces !== null && item.numberOfPieces !== undefined ? Number(item.numberOfPieces) : undefined,
  totalAmount: Number(item.totalAmount)
});


export class FastBillingController {
  private fastBillingService: FastBillingService;

  constructor() {
    this.fastBillingService = new FastBillingService();
  }

  createFastBilling = async (req: Request, res: Response): Promise<void> => {
    try {
      const data = req.body;

      const validationResult = fastBillingSchema.safeParse(data);
      if (!validationResult.success) {
        const errors = validationResult.error.issues.map(e => ({ path: e.path, message: e.message }));
        res.status(400).json({ message: "Validation failed", success: false, errors });
        return;
      }

      data.createdBy = req.user?.id ? BigInt(req.user.id) : undefined;
      const result = await this.fastBillingService.createFastBilling(data);
      res.status(201).json({
        success: true,
        message: "Fast Billing entry created successfully",
        data: {
          ...result,
          id: result.id.toString(),
          totalAmount: Number(result.totalAmount),
          items: (result.items || []).map(formatItem)
        }
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to create fast billing";
      res.status(400).json({ message });
    }
  };

  getFastBillings = 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 startDate = req.query.startDate as string;
      const endDate = req.query.endDate as string;
      const search = req.query.search as string;

      const result = await this.fastBillingService.getFastBillings(page, limit, startDate, endDate, search);
      res.json({
        success: true,
        data: result.data.map((entry: any) => ({
          ...entry,
          id: entry.id.toString(),
          totalAmount: Number(entry.totalAmount),
          items: (entry.items || []).map(formatItem)
        })),
        meta: result.meta,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch fast billings";
      res.status(400).json({ message });
    }
  };

  getFastBillingById = async (req: Request, res: Response): Promise<void> => {
    try {
      if (req.query.export === "pdf" || req.query.pdf === "true" || req.query.format === "pdf") {
        return this.exportFastBillingInvoicePdf(req, res);
      }
      const id = BigInt(req.params.id as string);
      const result = await this.fastBillingService.getFastBillingById(id);
      res.json({
        success: true,
        data: {
          ...result,
          id: result.id.toString(),
          totalAmount: Number(result.totalAmount),
          items: (result.items || []).map(formatItem)
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch fast billing";
      res.status(400).json({ message });
    }
  };

  updateFastBilling = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string);
      const data = req.body;

      const validationResult = fastBillingSchema.safeParse(data);
      if (!validationResult.success) {
        const errors = validationResult.error.issues.map(e => ({ path: e.path, message: e.message }));
        res.status(400).json({ message: "Validation failed", success: false, errors });
        return;
      }

      const result = await this.fastBillingService.updateFastBilling(id, data);
      res.json({
        success: true,
        message: "Fast Billing entry updated successfully",
        data: {
          ...result,
          id: result.id.toString(),
          totalAmount: Number(result.totalAmount),
          items: (result.items || []).map(formatItem)
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to update fast billing";
      res.status(400).json({ message });
    }
  };

  deleteFastBilling = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string);
      await this.fastBillingService.deleteFastBilling(id);
      res.json({
        success: true,
        message: "Fast Billing entry deleted successfully",
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to delete fast billing";
      res.status(400).json({ message });
    }
  };

  exportFastBillingsExcel = async (req: Request, res: Response): Promise<void> => {
    try {
      const startDate = req.query.startDate as string;
      const endDate = req.query.endDate as string;
      const search = req.query.search as string;

      const buffer = await this.fastBillingService.exportToExcel(startDate, endDate, search);

      res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
      res.setHeader('Content-Disposition', 'attachment; filename=FastBilling.xlsx');

      res.send(buffer);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to export fast billings to excel";
      res.status(400).json({ message });
    }
  };

  exportFastBillingInvoicePdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string);
      const lang = req.query.lang ? String(req.query.lang) : "en";
      const printSign = req.query.printSign === "true";
      await this.fastBillingService.exportInvoicePdf(id, res, { lang, printSign });
    } catch (error) {
      if (res.headersSent) {
        res.end();
      } else {
        const message = error instanceof Error ? error.message : "Failed to export fast billing invoice pdf";
        res.status(400).json({ message });
      }
    }
  };

  exportFastBillingsPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const startDate = req.query.startDate as string;
      const endDate = req.query.endDate as string;
      const search = req.query.search as string;

      await this.fastBillingService.exportListPdf(res, startDate, endDate, search);
    } catch (error) {
      if (res.headersSent) {
        res.end();
      } else {
        const message = error instanceof Error ? error.message : "Failed to export fast billings to pdf";
        res.status(400).json({ message });
      }
    }
  };
}
