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

const createStaffSchema = z.object({
  name: z.string().trim().min(1, "Name cannot be empty"),
  email: z.string().email("Invalid email format"),
  mobileNo: z.string().trim().regex(/^[6-9]\d{9}$/, "Invalid mobile number format").optional(),
  password: z.string().min(6, "Password must be at least 6 characters long"),
  roleId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)),
  status: z.boolean().optional(),
});

const updateStaffSchema = z.object({
  name: z.string().trim().min(1, "Name cannot be empty").optional(),
  email: z.string().email("Invalid email format").optional(),
  mobileNo: z.string().trim().regex(/^[6-9]\d{9}$/, "Invalid mobile number format").optional(),
  password: z.string().min(6, "Password must be at least 6 characters long").optional(),
  roleId: z.number().int().positive().or(z.string().regex(/^\d+$/).transform(Number)).optional(),
  status: z.boolean().optional(),
});

export class StaffController {
  constructor(private readonly staffService = new StaffService()) {}

  create = async (req: Request, res: Response): Promise<void> => {
    try {
      if (Number(req.user?.roleId) !== role.ADMIN) {
        res.status(412).json({
          message: "Access denied. Staff members are not permitted to create staff records.",
        });
        return;
      }

      const validatedData = createStaffSchema.parse(req.body);
      const result = await this.staffService.createStaff({
        ...validatedData,
        roleId: BigInt(validatedData.roleId),
      });
      res.status(201).json({ message: "Staff 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 staff";
      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;
      const roleIdParam = req.query.roleId as string;
      
      const roleId = roleIdParam ? BigInt(roleIdParam) : undefined;
      
      let statusFilter: boolean | undefined = undefined;
      if (req.query.status === "true") statusFilter = true;
      else if (req.query.status === "false") statusFilter = false;

      const result = await this.staffService.getStaff(page, limit, search, roleId, statusFilter);
      res.status(200).json({ message: "Staff fetched successfully", result });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to fetch staff";
      res.status(500).json({ message });
    }
  };

  getById = async (req: Request, res: Response): Promise<void> => {
    try {
      if (Number(req.user?.roleId) !== role.ADMIN) {
        res.status(412).json({
          message: "Access denied. Staff members are not permitted to edit staff records.",
        });
        return;
      }

      const id = BigInt(req.params.id as string | number);
      const currentUserId = req.user?.id !== undefined ? BigInt(req.user.id) : undefined;

      if (currentUserId !== undefined && id === currentUserId) {
        res.status(400).json({
          message: "You cannot update your own account in the Staff section.",
        });
        return;
      }

      const result = await this.staffService.getStaffById(id);
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Staff not found";
      res.status(404).json({ message });
    }
  };

  update = async (req: Request, res: Response): Promise<void> => {
    try {
      if (Number(req.user?.roleId) !== role.ADMIN) {
        res.status(412).json({
          message: "Access denied. Staff members are not permitted to edit staff records.",
        });
        return;
      }

      const id = BigInt(req.params.id as string | number);
      const currentUserId = req.user?.id !== undefined ? BigInt(req.user.id) : undefined;

      if (currentUserId !== undefined && id === currentUserId) {
        res.status(400).json({
          message: "You cannot update your own account in the Staff section.",
        });
        return;
      }

      const validatedData = updateStaffSchema.parse(req.body);
      
      const updateData: any = { ...validatedData };
      if (validatedData.roleId) updateData.roleId = BigInt(validatedData.roleId);

      const result = await this.staffService.updateStaff(id, updateData, currentUserId);
      res.status(200).json({ message: "Staff 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 staff";
      res.status(400).json({ message });
    }
  };

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