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

const updateSettingSchema = z.object({
  openingCashInHand: z
    .number()
    .min(0, "Opening Cash in Hand cannot be negative")
    .or(z.string().regex(/^\d+(\.\d+)?$/).transform(Number)),
  openingCashInBank: z
    .number()
    .min(0, "Opening Cash in Bank cannot be negative")
    .or(z.string().regex(/^\d+(\.\d+)?$/).transform(Number)),
  openingDate: z.string().min(1, "Opening date is required"),
  remarks: z.string().optional().nullable(),
});

const createTransferSchema = z.object({
  transferDate: z.string().min(1, "Transfer date is required"),
  amount: z
    .number()
    .gt(0, "Transfer amount must be greater than 0")
    .or(z.string().regex(/^\d+(\.\d+)?$/).transform(Number).refine((n) => n > 0, "Transfer amount must be greater than 0")),
  referenceNo: z.string().optional().nullable(),
  remarks: z.string().optional().nullable(),
});

export class CashBankController {
  /**
   * GET /api/cash-bank/balance
   * Live balances for Cash in Hand and Cash in Bank
   */
  getBalances = async (req: Request, res: Response) => {
    try {
      const balances = await cashBankService.getBalances();
      res.status(200).json({
        success: true,
        data: balances,
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        message: error?.message || "Failed to fetch cash & bank balances",
      });
    }
  };

  /**
   * POST /api/cash-bank/opening-balance
   * Set or update active initial / opening balances
   */
  updateOpeningBalance = async (req: Request, res: Response) => {
    try {
      const validated = updateSettingSchema.parse(req.body);
      const userId = (req as any).user?.id ? BigInt((req as any).user.id) : undefined;
      const result = await cashBankService.updateSetting(validated, userId);

      res.status(200).json({
        success: true,
        message: "Opening balances updated successfully",
        data: result,
      });
    } catch (error: any) {
      if (error instanceof z.ZodError) {
        const errors: Record<string, string> = {};
        error.issues.forEach((err) => {
          if (err.path[0]) errors[err.path[0].toString()] = err.message;
        });
        res.status(422).json({ success: false, message: "Validation failed", errors });
        return;
      }
      res.status(400).json({
        success: false,
        message: error?.message || "Failed to update opening balances",
      });
    }
  };

  /**
   * GET /api/cash-bank/transfers
   * Get Cash to Bank transfers
   */
  getTransfers = async (req: Request, res: Response) => {
    try {
      const { dateFrom, dateTo } = req.query;
      const transfers = await cashBankService.getTransfers(
        dateFrom ? String(dateFrom) : undefined,
        dateTo ? String(dateTo) : undefined
      );

      res.status(200).json({
        success: true,
        data: transfers,
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        message: error?.message || "Failed to fetch transfers",
      });
    }
  };

  /**
   * POST /api/cash-bank/transfers
   * Move Cash to Bank
   */
  createTransfer = async (req: Request, res: Response) => {
    try {
      const validated = createTransferSchema.parse(req.body);
      const userId = (req as any).user?.id ? BigInt((req as any).user.id) : undefined;
      const transfer = await cashBankService.createTransfer(validated, userId);

      res.status(201).json({
        success: true,
        message: "Cash moved to bank successfully",
        data: transfer,
      });
    } catch (error: any) {
      if (error instanceof z.ZodError) {
        const errors: Record<string, string> = {};
        error.issues.forEach((err) => {
          if (err.path[0]) errors[err.path[0].toString()] = err.message;
        });
        res.status(422).json({ success: false, message: "Validation failed", errors });
        return;
      }
      res.status(400).json({
        success: false,
        message: error?.message || "Failed to move cash to bank",
      });
    }
  };

  /**
   * DELETE /api/cash-bank/transfers/:id
   * Soft-delete a transfer
   */
  deleteTransfer = async (req: Request, res: Response) => {
    try {
      const idRaw = req.params.id;
      if (!idRaw) {
        res.status(400).json({ success: false, message: "Transfer ID is required" });
        return;
      }
      const id = BigInt(String(idRaw));
      const userId = (req as any).user?.id ? BigInt((req as any).user.id) : undefined;
      const result = await cashBankService.deleteTransfer(id, userId);

      res.status(200).json({
        success: true,
        message: "Transfer deleted successfully",
        data: result,
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        message: error?.message || "Failed to delete transfer",
      });
    }
  };

  /**
   * GET /api/cash-bank/ledger
   * Detailed Patru / Varavu ledger
   */
  getLedger = async (req: Request, res: Response) => {
    try {
      const { account, type, date, dateFrom, dateTo, search } = req.query;

      const ledger = await cashBankService.getLedger({
        account: account as any,
        type: type ? String(type) : undefined,
        date: date ? String(date) : undefined,
        dateFrom: dateFrom ? String(dateFrom) : undefined,
        dateTo: dateTo ? String(dateTo) : undefined,
        search: search ? String(search) : undefined,
      });

      res.status(200).json({
        success: true,
        data: ledger,
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        message: error?.message || "Failed to generate cash & bank ledger",
      });
    }
  };

  /**
   * GET /api/cash-bank/export/excel
   */
  exportExcel = async (req: Request, res: Response) => {
    try {
      const { account, type, date, dateFrom, dateTo, search } = req.query;

      await cashBankService.exportExcel(res, {
        account: account as any,
        type: type ? String(type) : undefined,
        date: date ? String(date) : undefined,
        dateFrom: dateFrom ? String(dateFrom) : undefined,
        dateTo: dateTo ? String(dateTo) : undefined,
        search: search ? String(search) : undefined,
      });
    } catch (error: any) {
      if (!res.headersSent) {
        res.status(500).json({
          success: false,
          message: error?.message || "Failed to export Excel",
        });
      }
    }
  };

  /**
   * GET /api/cash-bank/export/pdf
   */
  exportPdf = async (req: Request, res: Response) => {
    try {
      const { account, type, date, dateFrom, dateTo, search } = req.query;

      await cashBankService.exportPdf(res, {
        account: account as any,
        type: type ? String(type) : undefined,
        date: date ? String(date) : undefined,
        dateFrom: dateFrom ? String(dateFrom) : undefined,
        dateTo: dateTo ? String(dateTo) : undefined,
        search: search ? String(search) : undefined,
      });
    } catch (error: any) {
      if (!res.headersSent) {
        res.status(500).json({
          success: false,
          message: error?.message || "Failed to export PDF",
        });
      }
    }
  };
}

export default new CashBankController();
