import { AuthUser } from "@/contexts/auth/domain";
import { IUseCaseError, UseCaseError } from "@/contexts/common/application";
import { ICommonContext, InfrastructureError } from "@/contexts/common/infrastructure";
import { generateExpressError } from "@/contexts/common/infrastructure/express";
import { GetDealerByUserUseCase } from "@/contexts/sales/application";
import * as express from "express";
import httpStatus from "http-status";
import { registerDealerRepository } from "../../Dealer.repository";

interface AuthenticatedRequest extends express.Request {
  user?: AuthUser;
}

export const getDealerMiddleware = async (
  req: express.Request,
  res: express.Response,
  next: express.NextFunction
) => {
  const _req = req as AuthenticatedRequest;
  const user = _req.user as AuthUser;
  const { context } = res.locals as { context: ICommonContext };

  if (!user || !user.id) {
    handleError(req, res, UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, "User not found"));
  }

  registerDealerRepository(context);

  try {
    const dealerOrError = await new GetDealerByUserUseCase({
      adapter: context.adapter,
      repositoryManager: context.repositoryManager,
    }).execute({
      userId: user.id,
    });

    if (dealerOrError.isFailure) {
      handleError(req, res, dealerOrError.error);
    }

    res.locals.context = {
      ...context,
      dealer: dealerOrError.object,
    };

    next();
  } catch (e: unknown) {
    console.error("Error in getDealerMiddleware:", e as Error);
    handleError(req, res, e as UseCaseError);
  }
};

function handleError(req: express.Request, res: express.Response, error?: IUseCaseError) {
  const errorMappings: {
    [key: string]: { message: string; status: number; infraErrorCode: string };
  } = {
    [UseCaseError.NOT_FOUND_ERROR]: {
      message: "Dealer not found",
      status: httpStatus.NOT_FOUND,
      infraErrorCode: InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
    },
    [UseCaseError.INVALID_INPUT_DATA]: {
      message: "Dealer data not valid",
      status: httpStatus.UNPROCESSABLE_ENTITY,
      infraErrorCode: InfrastructureError.INVALID_INPUT_DATA,
    },
    [UseCaseError.REPOSITORY_ERROR]: {
      message: "Unexpected error",
      status: httpStatus.CONFLICT,
      infraErrorCode: InfrastructureError.UNEXCEPTED_ERROR,
    },
    [UseCaseError.UNEXCEPTED_ERROR]: {
      message: error?.message ?? "Unexcepted error",
      status: httpStatus.INTERNAL_SERVER_ERROR,
      infraErrorCode: InfrastructureError.UNEXCEPTED_ERROR,
    },
  };

  const { message, status, infraErrorCode } = error
    ? errorMappings[error.code]
    : {
        message: "Bad request",
        status: httpStatus.BAD_REQUEST,
        infraErrorCode: InfrastructureError.BAD_REQUEST,
      };

  const infraError = InfrastructureError.create(infraErrorCode, message, error);

  generateExpressError(req, res, status, message, infraError);
}
