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

const createCustomerSchema = z.object({
  name: z.string().trim().min(1, "Name cannot be empty"),
  tamilName: z.string().nullable().optional(),
  mobileNo: z.string().trim().regex(/^[6-9]\d{9}$/, "Invalid mobile number format"),
  address: z.string().nullable().optional(),
  stateId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)),
  districtId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)),
  openingBalance: z.number().optional().or(z.string().regex(/^\d+(\.\d+)?$/).transform(Number)),
  status: z.boolean().optional(),
});

const updateCustomerSchema = z.object({
  name: z.string().trim().min(1, "Name cannot be empty").optional(),
  tamilName: z.string().nullable().optional(),
  mobileNo: z.string().trim().regex(/^[6-9]\d{9}$/, "Invalid mobile number format").optional(),
  address: z.string().nullable().optional(),
  stateId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)).optional(),
  districtId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)).optional(),
  openingBalance: z.number().optional().or(z.string().regex(/^\d+(\.\d+)?$/).transform(Number)).optional(),
  status: z.boolean().optional(),
});

export class CustomerController {
  constructor(private readonly customerService = new CustomerService()) {}

  create = async (req: Request, res: Response): Promise<void> => {
    try {
      const validatedData = createCustomerSchema.parse(req.body);
      const result = await this.customerService.createCustomer({
        ...validatedData,
        stateId: BigInt(validatedData.stateId),
        districtId: BigInt(validatedData.districtId),
        createdBy: req.user?.id ? BigInt(req.user.id) : undefined,
      });
      res.status(201).json({ message: "Customer created successfully", result });
    } catch (error) {
      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({ message: "Validation failed", errors });
        return;
      }
      const message = error instanceof Error ? error.message : "Failed to create customer";
      res.status(400).json({ message });
    }
  };

  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;

      let statusFilter: boolean | undefined = undefined;
      if (req.query.status === "true") statusFilter = true;
      else if (req.query.status === "false") statusFilter = false;

      const result = await this.customerService.getCustomers(page, limit, search, statusFilter);
      res.status(200).json({ message: "Customers fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch customers";
      res.status(500).json({ message });
    }
  };

  getById = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string | number);
      const result = await this.customerService.getCustomerById(id);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Customer not found";
      res.status(404).json({ message });
    }
  };

  update = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string | number);
      const validatedData = updateCustomerSchema.parse(req.body);
      
      const updateData: any = { ...validatedData };
      if (validatedData.stateId) updateData.stateId = BigInt(validatedData.stateId);
      if (validatedData.districtId) updateData.districtId = BigInt(validatedData.districtId);

      const result = await this.customerService.updateCustomer(id, updateData);
      res.status(200).json({ message: "Customer updated successfully", result });
    } catch (error) {
      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({ message: "Validation failed", errors });
        return;
      }
      const message = error instanceof Error ? error.message : "Failed to update customer";
      res.status(400).json({ message });
    }
  };

  delete = async (req: Request, res: Response): Promise<void> => {
    try {
      const id = BigInt(req.params.id as string | number);
      await this.customerService.deleteCustomer(id);
      res.status(200).json({ message: "Customer deleted successfully" });
    } catch (error: any) {
      const message = error instanceof Error ? error.message : "Failed to delete customer";
      res.status(400).json({ message });
    }
  };

  downloadTemplate = async (_req: Request, res: Response): Promise<void> => {
    try {
      const buffer = await this.customerService.generateImportTemplate();
      res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
      res.setHeader("Content-Disposition", 'attachment; filename="customer-import-template.xlsx"');
      res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
      res.send(buffer);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to download import template";
      res.status(500).json({ message });
    }
  };

  importBulk = async (req: Request, res: Response): Promise<void> => {
    try {
      if (!req.file) {
        res.status(400).json({ message: "No file uploaded." });
        return;
      }
      const createdBy = req.user?.id ? BigInt(req.user.id) : undefined;
      const result = await this.customerService.importBulk(req.file.buffer, createdBy);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to import customers";
      res.status(400).json({ message });
    }
  };
}

