import type { Request, Response } from "express";
import { z } from "zod";
import { ArrivalSettlementService } from "../services/ArrivalSettlementService.js";
import { ArrivalSettlementPdf } from "../utils/pdf/ArrivalSettlementPdf.js";
import { ArrivalCustomPattiPdf } from "../utils/pdf/ArrivalCustomPattiPdf.js";

import { safeParseBigInt } from "../utils/parseHelper.js";

const createSettlementSchema = z.object({
  purchaseId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)),
  settlementDate: z.string().optional().nullable(),
  commissionPercent: z.number().min(0).max(100).optional().default(4.0),
  paidAmount: z.number().optional().default(0),
  paymentMode: z.enum(["CASH", "BANK", "UPI"]).optional().nullable(),
  remarks: z.string().optional().nullable(),
});

const saveCustomPattiSchema = z.object({
  purchaseId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)),
  pattiNo: z.string().optional().nullable(),
  settlementDate: z.string().optional().nullable(),
  items: z.array(z.any()),
  commissionPercent: z.number().min(0).max(100).optional(),
  freightDeducted: z.number().optional(),
  extraFreightDeducted: z.number().optional(),
  associationDeducted: z.number().optional(),
  unloadingDeducted: z.number().optional(),
  miscDeducted: z.number().optional(),
  advanceAdjusted: z.number().optional(),
  remarks: z.string().optional().nullable(),
});

export class ArrivalSettlementController {
  constructor(private readonly settlementService = new ArrivalSettlementService()) {}

  preview = async (req: Request, res: Response): Promise<void> => {
    try {
      const purchaseId = safeParseBigInt(req.params.purchaseId);
      if (!purchaseId) {
        res.status(400).json({ success: false, message: "Invalid arrival lot ID." });
        return;
      }
      const commissionRate = req.query.commissionPercent ? Number(req.query.commissionPercent) : 4.0;
      const preview = await this.settlementService.calculateSettlementPreview(purchaseId, commissionRate);

      res.status(200).json({ success: true, data: preview });
    } catch (error: any) {
      console.error("Arrival settlement preview error:", error);
      res.status(400).json({ success: false, message: error.message || "Failed to calculate settlement preview." });
    }
  };

  create = async (req: Request, res: Response): Promise<void> => {
    try {
      const validated = createSettlementSchema.parse(req.body);
      const userId = (req as any).user?.id ? BigInt((req as any).user.id) : undefined;
      const payload: {
        purchaseId: bigint;
        settlementDate?: Date;
        commissionPercent?: number;
        paidAmount?: number;
        paymentMode?: "CASH" | "BANK" | "UPI";
        remarks?: string;
      } = {
        purchaseId: BigInt(validated.purchaseId),
        settlementDate: validated.settlementDate ? new Date(validated.settlementDate) : new Date(),
        commissionPercent: validated.commissionPercent,
        paidAmount: validated.paidAmount,
      };
      if (validated.paymentMode) payload.paymentMode = validated.paymentMode;
      if (validated.remarks) payload.remarks = validated.remarks;

      const settlement = await this.settlementService.createSettlement(payload, userId);

      res.status(201).json({
        success: true,
        message: `P.Patti ${settlement.settlementNo} created successfully.`,
        data: settlement,
      });
    } 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 create P.Patti settlement." });
    }
  };

  list = async (req: Request, res: Response): Promise<void> => {
    try {
      const result = await this.settlementService.getAllSettlements(req.query as any);
      res.status(200).json({ success: true, ...result });
    } catch (error: any) {
      res.status(500).json({ success: false, message: error.message || "Failed to list settlements." });
    }
  };

  getById = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = String(req.params.id);
      const settlement = await this.settlementService.getSettlementById(BigInt(id));
      res.status(200).json({ success: true, data: settlement });
    } catch (error: any) {
      res.status(404).json({ success: false, message: error.message || "Settlement not found." });
    }
  };

  downloadPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = String(req.params.id);
      const settlement = await this.settlementService.getSettlementById(BigInt(id));
      await ArrivalSettlementPdf.generate(settlement, res);
    } catch (error: any) {
      res.status(500).json({ success: false, message: error.message || "Failed to generate settlement PDF." });
    }
  };

  // ─── Custom / Modified Patti Endpoints ─────────────────────────────────────

  getCustomPatti = async (req: Request, res: Response): Promise<void> => {
    try {
      const purchaseId = safeParseBigInt(req.params.purchaseId);
      if (!purchaseId) {
        res.status(400).json({ success: false, message: "Invalid arrival lot ID." });
        return;
      }
      const result = await this.settlementService.getCustomPatti(purchaseId);
      res.status(200).json({
        success: true,
        data: result.data,
        originalData: result.originalData,
        savedCustomData: result.savedCustomData,
        isCustomSaved: result.isCustomSaved,
        preview: result.preview,
      });
    } catch (error: any) {
      console.error("Get custom patti error:", error);
      res.status(400).json({ success: false, message: error.message || "Failed to get custom patti." });
    }
  };

  saveCustomPatti = async (req: Request, res: Response): Promise<void> => {
    try {
      const validated = saveCustomPattiSchema.parse(req.body);
      const userId = (req as any).user?.id ? BigInt((req as any).user.id) : undefined;

      const payload = {
        purchaseId: BigInt(validated.purchaseId),
        pattiNo: validated.pattiNo || undefined,
        settlementDate: validated.settlementDate ? new Date(validated.settlementDate) : undefined,
        items: validated.items,
        commissionPercent: validated.commissionPercent,
        freightDeducted: validated.freightDeducted,
        extraFreightDeducted: validated.extraFreightDeducted,
        associationDeducted: validated.associationDeducted,
        unloadingDeducted: validated.unloadingDeducted,
        miscDeducted: validated.miscDeducted,
        advanceAdjusted: validated.advanceAdjusted,
        remarks: validated.remarks || undefined,
      };

      const saved = await this.settlementService.saveCustomPatti(payload, userId);

      res.status(200).json({
        success: true,
        message: "Custom / Modified Patti saved successfully.",
        data: saved,
      });
    } 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;
      }
      console.error("Save custom patti error:", error);
      res.status(400).json({ success: false, message: error.message || "Failed to save custom patti." });
    }
  };

  downloadCustomPattiPdf = async (req: Request, res: Response): Promise<void> => {
    try {
      const purchaseId = safeParseBigInt(req.params.purchaseId);
      if (!purchaseId) {
        res.status(400).json({ success: false, message: "Invalid arrival lot ID." });
        return;
      }
      const result = await this.settlementService.getCustomPatti(purchaseId);
      const dataToPrint = result?.savedCustomData || result?.data;
      if (!dataToPrint) {
        res.status(404).json({ success: false, message: "Patti data not found." });
        return;
      }
      await ArrivalCustomPattiPdf.generate(dataToPrint, res);
    } catch (error: any) {
      console.error("Download custom patti PDF error:", error);
      res.status(500).json({ success: false, message: error.message || "Failed to generate custom patti PDF." });
    }
  };

  deleteCustomPatti = async (req: Request, res: Response): Promise<void> => {
    try {
      const purchaseId = safeParseBigInt(req.params.purchaseId);
      if (!purchaseId) {
        res.status(400).json({ success: false, message: "Invalid arrival lot ID." });
        return;
      }
      await this.settlementService.deleteCustomPatti(purchaseId);
      res.status(200).json({ success: true, message: "Custom Patti draft cleared (reverted to original)." });
    } catch (error: any) {
      console.error("Delete custom patti error:", error);
      res.status(400).json({ success: false, message: error.message || "Failed to delete custom patti." });
    }
  };
}

