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

const createEmployeeSchema = z.object({
  employeeCode: z.string().trim().optional(),
  name: z.string().trim().min(1, "Employee name is required").max(255),
  mobile: z.string().trim().nullable().optional(),
  designation: z.string().trim().nullable().optional(),
  status: z.boolean().optional().default(true),
}).strip();

const updateEmployeeSchema = createEmployeeSchema.partial().strip();

export class EmployeeController {
  constructor(private readonly employeeService = new EmployeeService()) {}

  create = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const validatedData = createEmployeeSchema.parse(req.body);
      const employee = await this.employeeService.create({
        ...validatedData,
        createdBy: req.user?.id ? BigInt(req.user.id) : undefined,
      } as any);
      res.status(201).json({ success: true, message: "Employee created successfully", data: employee });
    } 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({ message: "Validation failed", errors });
        return;
      }
      res.status(400).json({ message: error.message || "Failed to create employee" });
    }
  };

  findAll = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { page, limit, search, status } = req.query;
      const pageNum = page !== undefined ? Number(page) : 1;
      const limitNum = limit !== undefined ? Number(limit) : 50;
      const skipNum = (pageNum - 1) * limitNum;

      let statusBool: boolean | undefined = undefined;
      if (status === "true") statusBool = true;
      if (status === "false") statusBool = false;

      const result = await this.employeeService.findAll(
        skipNum,
        limitNum,
        search ? String(search) : undefined,
        statusBool
      );

      res.status(200).json({
        message: "Employees fetched successfully",
        result: {
          data: result.items,
          total: result.total,
          meta: {
            total: result.total,
            page: pageNum,
            limit: limitNum,
            totalPages: Math.ceil(result.total / limitNum),
          },
        },
      });
    } catch (error) {
      next(error);
    }
  };

  findById = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      const idStr = Array.isArray(id) ? id[0] : id;
      if (!idStr) {
        res.status(400).json({ message: "Employee ID is required" });
        return;
      }
      const employee = await this.employeeService.findById(BigInt(idStr));
      if (!employee) {
        res.status(404).json({ message: "Employee not found" });
        return;
      }
      res.status(200).json({ message: "Employee fetched successfully", result: employee });
    } catch (error) {
      next(error);
    }
  };

  update = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      const idStr = Array.isArray(id) ? id[0] : id;
      if (!idStr) {
        res.status(400).json({ message: "Employee ID is required" });
        return;
      }
      const validatedData = updateEmployeeSchema.parse(req.body);
      const employee = await this.employeeService.update(BigInt(idStr), validatedData as any);
      res.status(200).json({ message: "Employee updated successfully", result: employee });
    } 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({ message: "Validation failed", errors });
        return;
      }
      res.status(400).json({ message: error.message || "Failed to update employee" });
    }
  };

  delete = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { id } = req.params;
      const idStr = Array.isArray(id) ? id[0] : id;
      if (!idStr) {
        res.status(400).json({ message: "Employee ID is required" });
        return;
      }
      await this.employeeService.delete(BigInt(idStr));
      res.status(200).json({ message: "Employee deleted successfully" });
    } catch (error) {
      next(error);
    }
  };

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

