import { IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
import { ExpressController } from "@/contexts/common/infrastructure/express";

import { IServerError } from "@/contexts/common/domain/errors";
import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure";
import { GetQuoteUseCase } from "@/contexts/sales/application";
import { Quote } from "@/contexts/sales/domain";
import { ensureIdIsValid } from "@shared/contexts";
import { ISalesContext } from "../../../../Sales.context";
import { IReportQuoteReporter } from "./reporter/ReportQuote.reporter";

export class ReportQuoteController extends ExpressController {
  private useCase: GetQuoteUseCase;
  private reporter: IReportQuoteReporter;
  private context: ISalesContext;

  constructor(
    props: {
      useCase: GetQuoteUseCase;
      reporter: IReportQuoteReporter;
    },
    context: ISalesContext
  ) {
    super();

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

  async executeImpl(): Promise<any> {
    const { quoteId } = this.req.params;

    // 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);
    }

    try {
      const result = await this.useCase.execute({
        id: quoteIdOrError.object,
      });

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

      const quote = <Quote>result.object;

      return this.downloadPDF(await this.reporter.toPDF(quote, this.context), "quote.pdf");
    } catch (e: unknown) {
      return this.fail(e as IServerError);
    }
  }

  private _handleExecuteError(error: IUseCaseError) {
    let errorMessage: string;
    let infraError: IInfrastructureError;

    switch (error.code) {
      case UseCaseError.NOT_FOUND_ERROR:
        errorMessage = "Quote not found";

        infraError = InfrastructureError.create(
          InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
          errorMessage,
          error
        );

        return this.notFoundError(errorMessage, infraError);
        break;

      case UseCaseError.UNEXCEPTED_ERROR:
        errorMessage = error.message;

        infraError = InfrastructureError.create(
          InfrastructureError.UNEXCEPTED_ERROR,
          errorMessage,
          error
        );
        return this.internalServerError(errorMessage, infraError);
        break;

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