import { IUseCaseError, UseCaseError } from "@/contexts/common/application";
import { IServerError } from "@/contexts/common/domain/errors";
import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure";
import { ExpressController } from "@/contexts/common/infrastructure/express";
import { UpdateQuoteResponseOrError, UpdateQuoteUseCase } from "@/contexts/sales/application";
import { Quote } from "@/contexts/sales/domain";
import {
  IUpdateQuote_Request_DTO,
  IUpdateQuote_Response_DTO,
  ensureIdIsValid,
  ensureUpdateQuote_Request_DTOIsValid,
} from "@shared/contexts";
import { ISalesContext } from "../../../../Sales.context";
import { IUpdateQuotePresenter } from "./presenter/UpdateQuote.presenter";

export class UpdateQuoteController extends ExpressController {
  private useCase: UpdateQuoteUseCase;
  private presenter: IUpdateQuotePresenter;
  private context: ISalesContext;

  constructor(
    props: {
      useCase: UpdateQuoteUseCase;
      presenter: IUpdateQuotePresenter;
    },
    context: ISalesContext
  ) {
    super();

    const { useCase, presenter } = props;
    this.useCase = useCase;
    this.presenter = presenter;
    this.context = context;
  }

  async executeImpl() {
    try {
      const { quoteId } = this.req.params;
      const quoteDTO: IUpdateQuote_Request_DTO = this.req.body;

      // Validar ID
      const quoteIdOrError = ensureIdIsValid(quoteId);
      if (quoteIdOrError.isFailure) {
        const errorMessage = "Quote ID is not valid";
        const infraError = InfrastructureError.create(
          InfrastructureError.INVALID_INPUT_DATA,
          errorMessage,
          quoteIdOrError.error
        );
        return this.invalidInputError(errorMessage, infraError);
      }

      // Validar DTO de datos
      const quoteDTOOrError = ensureUpdateQuote_Request_DTOIsValid(quoteDTO);

      if (quoteDTOOrError.isFailure) {
        const errorMessage = "Quote data not valid";
        const infraError = InfrastructureError.create(
          InfrastructureError.INVALID_INPUT_DATA,
          errorMessage,
          quoteDTOOrError.error
        );
        return this.invalidInputError(errorMessage, infraError);
      }

      // Llamar al caso de uso
      const result: UpdateQuoteResponseOrError = await this.useCase.execute({
        id: quoteIdOrError.object,
        quoteDTO,
      });

      if (result.isFailure) {
        return this._handleExecuteError(result.error);
      }

      const quote = <Quote>result.object;

      return this.ok<IUpdateQuote_Response_DTO>(this.presenter.map(quote, this.context));
    } catch (e: unknown) {
      return this.fail(e as IServerError);
    }
  }

  private _handleExecuteError(error: IUseCaseError) {
    const createInfraError = (infrastructureCode: string, message: string) => {
      return InfrastructureError.create(infrastructureCode, message, error);
    };

    let errorMessage: string;
    let infraError: IInfrastructureError;

    switch (error.code) {
      case UseCaseError.NOT_FOUND_ERROR:
        errorMessage = "Quote not found";
        infraError = createInfraError(InfrastructureError.RESOURCE_NOT_FOUND_ERROR, errorMessage);
        return this.notFoundError(errorMessage, infraError);

      case UseCaseError.INVALID_INPUT_DATA:
        errorMessage = "Quote data not valid";
        infraError = createInfraError(InfrastructureError.INVALID_INPUT_DATA, errorMessage);
        return this.invalidInputError(errorMessage, infraError);

      case UseCaseError.REPOSITORY_ERROR:
        errorMessage = "Error updating quote";
        infraError = createInfraError(InfrastructureError.UNEXCEPTED_ERROR, errorMessage);
        return this.conflictError(errorMessage, infraError);

      case UseCaseError.UNEXCEPTED_ERROR:
        errorMessage = error.message;
        infraError = createInfraError(InfrastructureError.UNEXCEPTED_ERROR, errorMessage);
        return this.internalServerError(errorMessage, infraError);

      default:
        errorMessage = error.message;
        return this.clientError(errorMessage);
    }
  }
}
