import type { NextFunction, Request, Response } from "express";
import { CustomerReceiptService } from "../services/CustomerReceiptService.js";
import { z } from "zod";
import { generateCustomerReceiptExcel } from "../utils/excel/CustomerReceiptExcelExport.js";
import { safeParseBigInt } from "../utils/parseHelper.js";
import { CustomerReceiptPdf } from "../utils/pdf/CustomerReceiptPdf.js";

const customerReceiptService = new CustomerReceiptService();

const CreateReceiptSchema = z.object({
  customerId: z.coerce.number().int().positive(),
  receiptDate: z.string().min(1),
  amount: z.coerce.number().positive(),
  paymentMode: z.enum(["CASH", "BANK", "UPI"]),
  referenceNo: z.string().nullable().optional(),
  remarks: z.string().nullable().optional(),
});

const UpdateReceiptSchema = z.object({
  // customerId: z.coerce.number().int().positive().optional(),
  receiptDate: z.string().min(1).optional(),
  amount: z.coerce.number().positive().optional(),
  paymentMode: z.enum(["CASH", "BANK", "UPI"]).optional(),
  referenceNo: z.string().nullable().optional(),
  remarks: z.string().nullable().optional(),
});

export const createReceipt = async (
  req: Request,
  res: Response
): Promise<void> => {
  const parsed = CreateReceiptSchema.safeParse(req.body);
  if (!parsed.success) {
    res.status(400).json({
      message: "Validation failed",
      errors: parsed.error.flatten().fieldErrors,
    });
    return;
  }

  try {
    const data = {
      ...parsed.data,
      customerId: BigInt(parsed.data.customerId),
      createdBy: req.user?.id ? safeParseBigInt(req.user.id) : undefined,
    };
    const receipt = await customerReceiptService.createReceipt(data);
    res
      .status(201)
      .json({ message: "Receipt created successfully", result: receipt });
  } catch (err: any) {
    res.status(400).json({ message: err.message });
  }
};

export const getReceipts = async (
  req: Request,
  res: Response
): Promise<void> => {
  try {
    const page = Number(req.query.page) || 1;
    const limit = Number(req.query.limit) || 10;
    const customerId = safeParseBigInt(req.query.customerId);
    const dateFrom = req.query.dateFrom
      ? String(req.query.dateFrom)
      : undefined;
    const dateTo = req.query.dateTo ? String(req.query.dateTo) : undefined;
    const search = req.query.search ? String(req.query.search) : undefined;

    const result = await customerReceiptService.getReceipts(
      page,
      limit,
      customerId,
      dateFrom,
      dateTo,
      search
    );
    res.json({ message: "Receipts fetched successfully", result });
  } catch (err: any) {
    res.status(500).json({ message: err.message });
  }
};

export const exportReceiptExcel = async (
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> => {
  try {
    const customerId = safeParseBigInt(req.query.customerId);
    const dateFrom = req.query.dateFrom
      ? String(req.query.dateFrom)
      : undefined;
    const dateTo = req.query.dateTo ? String(req.query.dateTo) : undefined;
    const search = req.query.search ? String(req.query.search) : undefined;

    const receipts = await customerReceiptService.getReceiptsForExport(
      customerId,
      dateFrom,
      dateTo,
      search
    );

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

    const workbook = await generateCustomerReceiptExcel(receipts);

    res.setHeader(
      "Content-Type",
      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    );
    res.setHeader(
      "Content-Disposition",
      `attachment; filename=customer-receipts-${Date.now()}.xlsx`
    );

    await workbook.xlsx.write(res);
    res.end();
  } catch (error) {
    next(error);
  }
};

export const exportReceiptPdf = async (
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> => {
  try {
    const customerId = safeParseBigInt(req.query.customerId);
    const dateFrom = req.query.dateFrom ? String(req.query.dateFrom) : undefined;
    const dateTo = req.query.dateTo ? String(req.query.dateTo) : undefined;
    const search = req.query.search ? String(req.query.search) : undefined;

    const receipts = await customerReceiptService.getReceiptsForExport(
      customerId,
      dateFrom,
      dateTo,
      search
    );

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

    await CustomerReceiptPdf.generate(receipts, res, {
      ...(dateFrom !== undefined && { startDate: dateFrom }),
      ...(dateTo !== undefined && { endDate: dateTo }),
      ...(search !== undefined && { search }),
    });
  } catch (error) {
    next(error);
  }
};

export const getReceiptById = async (
  req: Request,
  res: Response
): Promise<void> => {
  try {
    const id = safeParseBigInt(req.params.id);
    if (!id) {
      res.status(400).json({ message: "Invalid receipt ID format" });
      return;
    }
    const receipt = await customerReceiptService.getReceiptById(id);
    res.json({ message: "Receipt fetched successfully", result: receipt });
  } catch (err: any) {
    res.status(404).json({ message: err.message });
  }
};

export const updateReceipt = async (
  req: Request,
  res: Response
): Promise<void> => {
  try {
    const id = safeParseBigInt(req.params.id);
    if (!id) {
      res.status(400).json({ message: "Invalid receipt ID format" });
      return;
    }
    const parsed = UpdateReceiptSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Validation failed",
        errors: parsed.error.flatten().fieldErrors,
      });
      return;
    }
    const userId = req.user?.id ? safeParseBigInt(req.user.id) : undefined;
    const receipt = await customerReceiptService.updateReceipt(id, parsed.data, userId);
    res.json({ message: "Receipt updated successfully", result: receipt });
  } catch (err: any) {
    res.status(400).json({ message: err.message });
  }
};

export const deleteReceipt = async (
  req: Request,
  res: Response
): Promise<void> => {
  try {
    const id = safeParseBigInt(req.params.id);
    if (!id) {
      res.status(400).json({ message: "Invalid receipt ID format" });
      return;
    }
    const userId = req.user?.id ? safeParseBigInt(req.user.id) : undefined;
    await customerReceiptService.deleteReceipt(id, userId);
    res.json({ message: "Receipt deleted successfully" });
  } catch (err: any) {
    res.status(400).json({ message: err.message });
  }
};

export const getReceiptMeta = async (
  _req: Request,
  res: Response
): Promise<void> => {
  try {
    const meta = await customerReceiptService.getReceiptMeta();
    res.json({ message: "Receipt meta fetched", result: meta });
  } catch (err: any) {
    res.status(500).json({ message: err.message });
  }
};

export const sendWhatsappReceipt = async (
  req: Request,
  res: Response
): Promise<void> => {
  try {
    const id = safeParseBigInt(req.params.id);
    if (!id) {
      res.status(400).json({ message: "Invalid receipt ID format" });
      return;
    }
    await customerReceiptService.sendWhatsappReceipt(id);
    res.json({ message: "WhatsApp message sent successfully" });
  } catch (error: any) {
    res.status(400).json({ message: error.message });
  }
};

