import { Response } from "express";
import { CustomRequest } from "../interfaces/auth";
import { STATUS_CODES } from "../constants/statusCodes";
import { FUEL_REQUEST_CONSTANTS } from "../constants/messages";
import ResponseUtil from "../utils/Response/responseUtils";
import {
  sendFuelRequestSchema,
  fuelRequestListSchema,
  fuelRequestIdParamSchema,
} from "../validators/fuelRequestValidator";
import {
  sendFuelRequest,
  getFuelRequests,
  transferFuel,
  rejectFuelRequest,
} from "../services/fuelRequestService";

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_REQUEST":
      ResponseUtil.errorResponse(res, STATUS_CODES.BAD_REQUEST, FUEL_REQUEST_CONSTANTS.CANNOT_SELF_REQUEST);
      break;
    case "NOT_CONNECTED":
      ResponseUtil.errorResponse(res, STATUS_CODES.FORBIDDEN, FUEL_REQUEST_CONSTANTS.NOT_CONNECTED);
      break;
    case "BLOCKED":
      ResponseUtil.errorResponse(res, STATUS_CODES.FORBIDDEN, FUEL_REQUEST_CONSTANTS.BLOCKED);
      break;
    case "RECEIVER_NOT_FOUND":
      ResponseUtil.errorResponse(res, STATUS_CODES.NOT_FOUND, "Receiver not found");
      break;
    case "NOT_FOUND":
      ResponseUtil.errorResponse(res, STATUS_CODES.NOT_FOUND, FUEL_REQUEST_CONSTANTS.NOT_FOUND);
      break;
    case "FORBIDDEN":
      ResponseUtil.errorResponse(res, STATUS_CODES.FORBIDDEN, FUEL_REQUEST_CONSTANTS.FORBIDDEN);
      break;
    case "ALREADY_PROCESSED":
      ResponseUtil.errorResponse(res, STATUS_CODES.CONFLICT, FUEL_REQUEST_CONSTANTS.ALREADY_PROCESSED);
      break;
    case "INSUFFICIENT_FUNDS":
      ResponseUtil.errorResponse(res, STATUS_CODES.BAD_REQUEST, FUEL_REQUEST_CONSTANTS.INSUFFICIENT_FUNDS);
      break;
    default:
      ResponseUtil.errorResponse(res, STATUS_CODES.INTERNAL_SERVER_ERROR, err.message);
  }
}

/**
 * POST /api/v1/fuel-requests
 * Send a fuel payment request to an accepted connection.
 */
export const createFuelRequest = async (req: CustomRequest, res: Response) => {
  try {
    const { receiverUserId, amount, message } = await sendFuelRequestSchema.parseAsync(req.body);
    const result = await sendFuelRequest(req.userId!, receiverUserId, amount, message);
    ResponseUtil.successResponse(res, STATUS_CODES.SUCCESS, result, FUEL_REQUEST_CONSTANTS.SENT);
  } catch (err) {
    if (err instanceof Error && ["CANNOT_SELF_REQUEST", "NOT_CONNECTED", "RECEIVER_NOT_FOUND", "BLOCKED"].includes(err.message)) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * GET /api/v1/fuel-requests/sent
 * List fuel requests sent by the logged-in user.
 * Query: page, limit, status
 */
export const getSentFuelRequests = async (req: CustomRequest, res: Response) => {
  try {
    const { page, limit, status } = await fuelRequestListSchema.parseAsync(req.query);
    const result = await getFuelRequests(req.userId!, "sent", page, limit, status);
    ResponseUtil.successResponse(res, STATUS_CODES.SUCCESS, result, FUEL_REQUEST_CONSTANTS.FETCHED);
  } catch (err) {
    ResponseUtil.handleError(res, err);
  }
};

/**
 * GET /api/v1/fuel-requests/received
 * List fuel requests received by the logged-in user.
 * Query: page, limit, status
 */
export const getReceivedFuelRequests = async (req: CustomRequest, res: Response) => {
  try {
    const { page, limit, status } = await fuelRequestListSchema.parseAsync(req.query);
    const result = await getFuelRequests(req.userId!, "received", page, limit, status);
    ResponseUtil.successResponse(res, STATUS_CODES.SUCCESS, result, FUEL_REQUEST_CONSTANTS.FETCHED);
  } catch (err) {
    ResponseUtil.handleError(res, err);
  }
};

/**
 * PATCH /api/v1/fuel-requests/:requestId/transfer
 * Accept and pay a pending fuel request (receiver only).
 * Debits receiver's wallet, credits sender's wallet atomically.
 */
export const transferFuelPayment = async (req: CustomRequest, res: Response) => {
  try {
    const { requestId } = await fuelRequestIdParamSchema.parseAsync(req.params);
    const result = await transferFuel(requestId, req.userId!);
    ResponseUtil.successResponse(res, STATUS_CODES.SUCCESS, result, FUEL_REQUEST_CONSTANTS.TRANSFERRED);
  } catch (err) {
    if (err instanceof Error && ["NOT_FOUND", "FORBIDDEN", "ALREADY_PROCESSED", "INSUFFICIENT_FUNDS"].includes(err.message)) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * PATCH /api/v1/fuel-requests/:requestId/reject
 * Reject a pending fuel request (receiver only).
 */
export const rejectFuelPayment = async (req: CustomRequest, res: Response) => {
  try {
    const { requestId } = await fuelRequestIdParamSchema.parseAsync(req.params);
    const result = await rejectFuelRequest(requestId, req.userId!);
    ResponseUtil.successResponse(res, STATUS_CODES.SUCCESS, result, FUEL_REQUEST_CONSTANTS.REJECTED);
  } catch (err) {
    if (err instanceof Error && ["NOT_FOUND", "FORBIDDEN", "ALREADY_PROCESSED"].includes(err.message)) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};
