import { Response } from "express";
import { CustomRequest } from "../interfaces/auth";
import { STATUS_CODES } from "../constants/statusCodes";
import { BLOCK_CONSTANTS } from "../constants/messages";
import ResponseUtil from "../utils/Response/responseUtils";
import {
  createBlockSchema,
  blockUserIdParamSchema,
  blockListSchema,
} from "../validators/blockValidator";
import {
  blockUser,
  unblockUser,
  listBlockedUsers,
} from "../services/blockService";

function handleServiceError(res: Response, err: unknown): void {
  if (!(err instanceof Error)) {
    ResponseUtil.errorResponse(
      res,
      STATUS_CODES.INTERNAL_SERVER_ERROR,
      "An unexpected error occurred",
    );
    return;
  }

  switch (err.message) {
    case "CANNOT_SELF_BLOCK":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        BLOCK_CONSTANTS.CANNOT_SELF_BLOCK,
      );
      break;
    case "USER_NOT_FOUND":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        BLOCK_CONSTANTS.USER_NOT_FOUND,
      );
      break;
    case "ALREADY_BLOCKED":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.CONFLICT,
        BLOCK_CONSTANTS.ALREADY_BLOCKED,
      );
      break;
    case "NOT_BLOCKED":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        BLOCK_CONSTANTS.NOT_BLOCKED,
      );
      break;
    default:
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.INTERNAL_SERVER_ERROR,
        err.message,
      );
  }
}

/**
 * POST /api/v1/blocks
 * Block another user (one-way; enforcement is either direction).
 */
export const createBlock = async (req: CustomRequest, res: Response) => {
  try {
    const { userId } = await createBlockSchema.parseAsync(req.body);
    const result = await blockUser(req.userId!, userId);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      result,
      BLOCK_CONSTANTS.BLOCKED,
    );
  } catch (err) {
    if (
      err instanceof Error &&
      ["CANNOT_SELF_BLOCK", "USER_NOT_FOUND", "ALREADY_BLOCKED"].includes(
        err.message,
      )
    ) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * DELETE /api/v1/blocks/:userId
 * Unblock a user previously blocked by the current user.
 */
export const removeBlock = async (req: CustomRequest, res: Response) => {
  try {
    const { userId } = await blockUserIdParamSchema.parseAsync(req.params);
    await unblockUser(req.userId!, userId);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      {},
      BLOCK_CONSTANTS.UNBLOCKED,
    );
  } catch (err) {
    if (err instanceof Error && err.message === "NOT_BLOCKED") {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * GET /api/v1/blocks
 * List users blocked by the current user.
 */
export const getBlockedUsers = async (req: CustomRequest, res: Response) => {
  try {
    const { page, limit } = await blockListSchema.parseAsync(req.query);
    const result = await listBlockedUsers(req.userId!, page, limit);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      result,
      BLOCK_CONSTANTS.LIST_FETCHED,
    );
  } catch (err) {
    ResponseUtil.handleError(res, err);
  }
};
