import { Request, Response } from "express";
import { Role, RiskStatus } from "@prisma/client";

import { AuthenticatedRequest } from "../../middleware/auth";
import { userService, CreateUserData, UpdateUserData } from "./users.service";
import { UserListParams } from "./users.repository";
import { handleError } from "../../utils/http";

export class UserController {
  /**
   * List users with pagination and filtering
   */
  async listUsers(req: Request, res: Response) {
    try {
      const params: UserListParams = {
        page: Math.max(parseInt((req.query.page as string) || "1", 10), 1),
        limit: Math.max(parseInt((req.query.limit as string) || "25", 10), 1),
        search: ((req.query.search as string) || "").trim(),
        risks: ((req.query.risks as string) || "")
          .split(",")
          .map((r) => r.trim())
          .filter((r) => !!r),
        sortBy: (req.query.sortBy as string) || "",
        sortDir:
          ((req.query.sortDir as string) || "asc").toLowerCase() === "desc"
            ? "desc"
            : "asc",
        roleType: ((req.query.roleType as string) || "user").toLowerCase() as
          | "user"
          | "admin",
      };

      const result = await userService.getUsers(params);
      res.json({
        items: result.items,
        total: result.total,
        page: params.page,
        limit: params.limit,
      });
    } catch (error: any) {
      return handleError(res, "Failed to fetch users", error);
    }
  }

  /**
   * Get login activities for a specific user
   */
  async getUserLoginActivities(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const page = Math.max(parseInt((req.query.page as string) || "1", 10), 1);
      const limit = Math.max(
        parseInt((req.query.limit as string) || "25", 10),
        1
      );

      const result = await userService.getUserLoginActivities(id, page, limit);
      res.json({ items: result.items, total: result.total, page, limit });
    } catch (error: any) {
      return handleError(res, "Failed to fetch user login activities", error);
    }
  }

  /**
   * Get user login activity logs
   */
  async getUserLogs(req: Request, res: Response) {
    try {
      const page = Math.max(parseInt((req.query.page as string) || "1", 10), 1);
      const limit = Math.max(
        parseInt((req.query.limit as string) || "25", 10),
        1
      );
      const search = ((req.query.search as string) || "").trim();

      const result = await userService.getUserLogs(page, limit, search);
      res.json({
        items: result.items,
        total: result.total,
        page,
        limit,
      });
    } catch (error: any) {
      return handleError(res, "Failed to fetch login logs", error);
    }
  }

  /**
   * Resend invitation email to a user
   */
  async resendInvitation(req: Request, res: Response) {
    try {
      const { id } = req.params;
      await userService.resendInvitation(id);
      res.json({ message: "Invitation email sent" });
    } catch (error: any) {
      if (error.message === "User not found") {
        return res.status(404).json({ error: error.message });
      }
      if (
        error.message ===
          "Invitations are not applicable for end-user accounts" ||
        error.message === "User is already activated"
      ) {
        return res.status(400).json({ error: error.message });
      }
      res
        .status(500)
        .json({ error: "Failed to send invitation", details: error.message });
    }
  }

  /**
   * Get a single user by ID
   */
  async getUser(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const user = await userService.getUserById(id);
      res.json(user);
    } catch (error: any) {
      if (error.message === "User not found") {
        return res.status(404).json({ error: error.message });
      }
      return handleError(res, "Failed to fetch user", error);
    }
  }

  /**
   * Create a new user
   */
  async createUser(req: AuthenticatedRequest, res: Response) {
    try {
      const data: CreateUserData = {
        firstName: req.body.firstName,
        lastName: req.body.lastName,
        email: req.body.email,
        password: req.body.password,
        title: req.body.title,
        imageUrl: req.body.imageUrl,
        riskStatus: req.body.riskStatus || RiskStatus.LOW_RISK,
        role: req.body.role || Role.USER,
        managerId: req.body.managerId,
      };

      const requesterRole = req.user?.role as Role | undefined;
      const requesterId = req.user?.userId as string | undefined;

      const user = await userService.createUser(
        data,
        requesterRole,
        requesterId
      );
      res.status(201).json(user);
    } catch (error: any) {
      if (error.message === "Missing required fields") {
        return res.status(400).json({ error: error.message });
      }
      if (error.message === "Email already exists") {
        return res.status(409).json({ error: error.message });
      }
      if (
        error.message === "Admins may only create end-user accounts" ||
        error.message === "Only Managers can create Admin accounts"
      ) {
        return res
          .status(403)
          .json({ error: "Forbidden", details: error.message });
      }
      if (
        error.message === "Could not determine manager for the new Admin" ||
        error.message === "managerId must reference an existing Manager"
      ) {
        return res.status(400).json({
          error: error.message.includes("manager")
            ? "Invalid manager assignment"
            : "Invalid manager",
          details: error.message,
        });
      }
      return handleError(res, "Failed to create user", error);
    }
  }

  /**
   * Update a user
   */
  async updateUser(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const data: UpdateUserData = {
        firstName: req.body.firstName,
        lastName: req.body.lastName,
        email: req.body.email,
        title: req.body.title,
        riskStatus: req.body.riskStatus,
        imageUrl: req.body.imageUrl,
        isLocked: req.body.isLocked,
        role: req.body.role,
        managerId: req.body.managerId,
      };

      const requesterRole = (req as AuthenticatedRequest).user?.role as
        | Role
        | undefined;
      const requesterId = (req as AuthenticatedRequest).user?.userId as
        | string
        | undefined;

      const user = await userService.updateUser(
        id,
        data,
        requesterRole,
        requesterId
      );
      res.json(user);
    } catch (error: any) {
      if (error.message === "User not found") {
        return res.status(404).json({ error: error.message });
      }
      if (
        error.message === "Admins may not change role to Admin/Manager" ||
        error.message === "Admins may not assign or reassign Admins" ||
        error.message === "Only Managers can assign/reassign Admins"
      ) {
        return res
          .status(403)
          .json({ error: "Forbidden", details: error.message });
      }
      if (
        error.message === "managerId may only be set for Admin accounts" ||
        error.message === "Could not determine manager for the Admin"
      ) {
        return res.status(400).json({
          error: error.message.includes("manager")
            ? "Invalid manager assignment"
            : "Invalid assignment",
          details: error.message,
        });
      }
      if (error.message === "managerId must reference an existing Manager") {
        return res
          .status(400)
          .json({ error: "Invalid manager", details: error.message });
      }
      return handleError(res, "Failed to update user", error);
    }
  }

  /**
   * Toggle user lock status
   */
  async toggleLock(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const user = await userService.toggleUserLock(id);
      res.json(user);
    } catch (error: any) {
      if (error.message === "User not found") {
        return res.status(404).json({ error: error.message });
      }
      return handleError(res, "Failed to lock/unlock user", error);
    }
  }

  /**
   * Delete a single user
   */
  async deleteUser(req: Request, res: Response) {
    try {
      const { id } = req.params;
      const requesterRole = (req as AuthenticatedRequest).user?.role;

      await userService.deleteUser(id, requesterRole);
      res.status(204).send();
    } catch (error: any) {
      if (error.message === "User not found") {
        return res.status(404).json({ error: error.message });
      }
      if (error.message === "Admins may only delete regular users") {
        return res.status(403).json({
          error: "Forbidden",
          details: error.message,
        });
      }
      return handleError(res, "Failed to delete user", error);
    }
  }

  /**
   * Bulk delete users
   */
  async deleteUsers(req: Request, res: Response) {
    try {
      const { ids } = req.body;
      const requesterRole = (req as AuthenticatedRequest).user?.role;

      await userService.deleteUsers(ids, requesterRole);
      res.status(204).send();
    } catch (error: any) {
      if (error.message === "No user IDs provided") {
        return res.status(400).json({ error: error.message });
      }
      if (error.message === "Admins may only delete regular users") {
        return res.status(403).json({
          error: "Forbidden",
          details: error.message,
        });
      }
      return handleError(res, "Failed to delete users", error);
    }
  }
}

export const userController = new UserController();
