import { Response } from "express";
import { CustomRequest } from "../interfaces/auth";
import { STATUS_CODES } from "../constants/statusCodes";
import { TRIP_SHARE_CONSTANTS } from "../constants/messages";
import ResponseUtil from "../utils/Response/responseUtils";
import {
  shareTripSchema,
  tripShareListSchema,
  tripShareIdParamSchema,
} from "../validators/tripShareValidator";
import {
  shareTrip,
  getSharedTrips,
  getSharedTripById,
  revokeTripShare,
} from "../services/tripShareService";

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_SHARE":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        TRIP_SHARE_CONSTANTS.CANNOT_SELF_SHARE,
      );
      break;
    case "NOT_CONNECTED":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.FORBIDDEN,
        TRIP_SHARE_CONSTANTS.NOT_CONNECTED,
      );
      break;
    case "BLOCKED":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.FORBIDDEN,
        TRIP_SHARE_CONSTANTS.BLOCKED,
      );
      break;
    case "RECIPIENT_NOT_FOUND":
      ResponseUtil.errorResponse(res, STATUS_CODES.NOT_FOUND, "Recipient not found");
      break;
    case "TRIP_NOT_FOUND":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        TRIP_SHARE_CONSTANTS.TRIP_NOT_FOUND,
      );
      break;
    case "ALREADY_SHARED":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.CONFLICT,
        TRIP_SHARE_CONSTANTS.ALREADY_SHARED,
      );
      break;
    case "NOT_FOUND":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        TRIP_SHARE_CONSTANTS.NOT_FOUND,
      );
      break;
    case "FORBIDDEN":
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.FORBIDDEN,
        TRIP_SHARE_CONSTANTS.FORBIDDEN,
      );
      break;
    default:
      ResponseUtil.errorResponse(
        res,
        STATUS_CODES.INTERNAL_SERVER_ERROR,
        err.message,
      );
  }
}

const SHARE_CREATE_ERRORS = [
  "CANNOT_SELF_SHARE",
  "NOT_CONNECTED",
  "BLOCKED",
  "RECIPIENT_NOT_FOUND",
  "TRIP_NOT_FOUND",
  "ALREADY_SHARED",
];

/**
 * POST /api/v1/trip-shares
 * Share a trip with an accepted connection (read-only for recipient).
 */
export const createTripShare = async (req: CustomRequest, res: Response) => {
  try {
    const { tripId, sharedWithUserId } = await shareTripSchema.parseAsync(
      req.body,
    );
    const result = await shareTrip(req.userId!, tripId, sharedWithUserId);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      result,
      TRIP_SHARE_CONSTANTS.SHARED,
    );
  } catch (err) {
    if (err instanceof Error && SHARE_CREATE_ERRORS.includes(err.message)) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * GET /api/v1/trip-shares
 * List shared trips (received by default, or sent).
 */
export const listTripShares = async (req: CustomRequest, res: Response) => {
  try {
    const { type, page, limit } = await tripShareListSchema.parseAsync(
      req.query,
    );
    const result = await getSharedTrips(req.userId!, type, page, limit);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      result,
      TRIP_SHARE_CONSTANTS.FETCHED,
    );
  } catch (err) {
    ResponseUtil.handleError(res, err);
  }
};

/**
 * GET /api/v1/trip-shares/:shareId
 * Full shared trip detail (recipient: canEdit false).
 */
export const getTripShareDetail = async (req: CustomRequest, res: Response) => {
  try {
    const { shareId } = await tripShareIdParamSchema.parseAsync(req.params);
    const result = await getSharedTripById(shareId, req.userId!);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      result,
      TRIP_SHARE_CONSTANTS.DETAIL_FETCHED,
    );
  } catch (err) {
    if (
      err instanceof Error &&
      ["NOT_FOUND", "FORBIDDEN", "TRIP_NOT_FOUND"].includes(err.message)
    ) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};

/**
 * DELETE /api/v1/trip-shares/:shareId
 * Revoke an active share (owner only).
 */
export const deleteTripShare = async (req: CustomRequest, res: Response) => {
  try {
    const { shareId } = await tripShareIdParamSchema.parseAsync(req.params);
    await revokeTripShare(shareId, req.userId!);
    ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      {},
      TRIP_SHARE_CONSTANTS.REVOKED,
    );
  } catch (err) {
    if (
      err instanceof Error &&
      ["NOT_FOUND", "FORBIDDEN"].includes(err.message)
    ) {
      handleServiceError(res, err);
    } else {
      ResponseUtil.handleError(res, err);
    }
  }
};
