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

const createStateSchema = z.object({
  name: z.string({
    message: "State name must be a string",
  }).trim().min(1, "State name cannot be empty"),
  tamilName: z.string({
    message: "Tamil name must be a string",
  }).optional(),
  status: z.boolean({
    message: "Status must be a boolean",
  }).optional(),
});

const updateStateSchema = z.object({
  name: z.string({
    message: "State name must be a string",
  }).trim().min(1, "State name cannot be empty").optional(),
  tamilName: z.string({
    message: "Tamil name must be a string",
  }).optional(),
  status: z.boolean({
    message: "Status must be a boolean",
  }).optional(),
});

export class StateController {
  constructor(private readonly stateService = new StateService()) { }

  create = async (req: Request, res: Response): Promise<void> => {
    try {
      const validatedData = createStateSchema.parse(req.body);
      const result = await this.stateService.createState({
        ...validatedData,
        createdBy: req.user?.id ? BigInt(req.user.id) : undefined,
      } as any);
      res.status(201).json({ message: "State created successfully", result });
    } catch (error) {
      if (error instanceof z.ZodError) {
        const errors: Record<string, string> = {};
        error?.issues?.forEach((err: any) => {
          if (err.path[0]) {
            errors[err.path[0].toString()] = err.message;
          }
        });
        res.status(422).json({ message: "Validation failed", errors });
        return;
      }
      if ((error as any)?.code === "P2002") {
        const target = (error as any)?.meta?.target;
        const targetStr = Array.isArray(target) ? target.join(",") : String(target || "");
        if (targetStr.includes("tamil_name") || targetStr.includes("tamilName")) {
          res.status(400).json({ message: "State Tamil name already exists" });
          return;
        }
        res.status(400).json({ message: "State name already exists" });
        return;
      }
      const message = error instanceof Error ? error.message : "Failed to create state";
      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.stateService.getStates(page, limit, search, statusFilter);
      res.status(200).json({ message: "States fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch states";
      res.status(500).json({ message });
    }
  };

  getActiveList = async (req: Request, res: Response): Promise<void> => {
    try {
      const result = await this.stateService.getActiveStates();
      res.status(200).json({ message: "Active states fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch active states";
      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.stateService.getStateById(id);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "State 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 = updateStateSchema.parse(req.body);
      const result = await this.stateService.updateState(id, validatedData as any);
      res.status(200).json(result);
    } catch (error) {
      if (error instanceof z.ZodError) {
        const errors: Record<string, string> = {};
        error?.issues?.forEach((err: any) => {
          if (err.path[0]) {
            errors[err.path[0].toString()] = err.message;
          }
        });
        res.status(422).json({ message: "Validation failed", errors });
        return;
      }
      if ((error as any)?.code === "P2002") {
        const target = (error as any)?.meta?.target;
        const targetStr = Array.isArray(target) ? target.join(",") : String(target || "");
        if (targetStr.includes("tamil_name") || targetStr.includes("tamilName")) {
          res.status(400).json({ message: "State Tamil name already exists" });
          return;
        }
        res.status(400).json({ message: "State name already exists" });
        return;
      }
      const message = error instanceof Error ? error.message : "Failed to update state";
      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.stateService.deleteState(id);
      res.status(200).json({ message: "State deleted successfully" });
    } catch (error: any) {
      if (error?.code === "P2003") {
        res.status(409).json({ message: "Cannot be deleted as this is used in another module." });
        return;
      }
      const message = error instanceof Error ? error.message : "Failed to delete state";
      res.status(400).json({ message });
    }
  };

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