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

const createSupplierSchema = 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 updateSupplierSchema = 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(),
  status: z.boolean().optional(),
});

export class SupplierController {
  constructor(private readonly supplierService = new SupplierService()) {}

  create = async (req: Request, res: Response): Promise<void> => {
    try {
      const validatedData = createSupplierSchema.parse(req.body);
      const result = await this.supplierService.createSupplier({
        ...validatedData,
        stateId: BigInt(validatedData.stateId),
        districtId: BigInt(validatedData.districtId),
        createdBy: req.user?.id ? BigInt(req.user.id) : undefined,
      });
      res.status(201).json({ message: "Supplier 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 supplier";
      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.supplierService.getSuppliers(page, limit, search, statusFilter);
      res.status(200).json({ message: "Suppliers fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch suppliers";
      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.supplierService.getSupplierById(id);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Supplier 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 = updateSupplierSchema.parse(req.body);
      
      const updateData: any = { ...validatedData };
      if (validatedData.stateId) updateData.stateId = BigInt(validatedData.stateId);
      if (validatedData.districtId) updateData.districtId = BigInt(validatedData.districtId);
      delete updateData.openingBalance;

      const result = await this.supplierService.updateSupplier(id, updateData);
      res.status(200).json({ message: "Supplier 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 supplier";
      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.supplierService.deleteSupplier(id);
      res.status(200).json({ message: "Supplier deleted successfully" });
    } catch (error: any) {
      const message = error instanceof Error ? error.message : "Failed to delete supplier";
      res.status(400).json({ message });
    }
  };

  getStatesAndDistricts = async (req: Request, res: Response): Promise<void> => {
    try {
      const result = await this.supplierService.getStatesAndDistricts();
      res.status(200).json({ message: "Locations fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch locations";
      res.status(500).json({ message });
    }
  };

  downloadTemplate = async (_req: Request, res: Response): Promise<void> => {
    try {
      const buffer = await this.supplierService.generateImportTemplate();
      res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
      res.setHeader("Content-Disposition", 'attachment; filename="supplier-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.supplierService.importBulk(req.file.buffer, createdBy);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to import suppliers";
      res.status(400).json({ message });
    }
  };
}

