import { IInvoicingContext } from "#/server/intrastructure";
import { ExpressController } from "@rdx/core";
import { IUpdateCustomerInvoicePresenter } from "./presenter";

export class UpdateCustomerInvoiceController extends ExpressController {
  private useCase: UpdateCustomerInvoiceUseCase2;
  private presenter: IUpdateCustomerInvoicePresenter;
  private context: IInvoicingContext;

  constructor(
    props: {
      useCase: UpdateCustomerInvoiceUseCase;
      presenter: IUpdateCustomerInvoicePresenter;
    },
    context: IInvoicingContext
  ) {
    super();

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

  async executeImpl(): Promise<any> {
    const { customerInvoiceId } = this.req.params;
    const request: IUpdateCustomerInvoice_DTO = this.req.body;

    if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, customerInvoiceId).isFailure) {
      return this.invalidInputError("CustomerInvoice Id param is required!");
    }

    const idOrError = UniqueID.create(customerInvoiceId);
    if (idOrError.isFailure) {
      return this.invalidInputError("Invalid customerInvoice Id param!");
    }

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

      if (result.isFailure) {
        const { error } = result;

        switch (error.code) {
          case UseCaseError.NOT_FOUND_ERROR:
            return this.notFoundError("CustomerInvoice not found", error);

          case UseCaseError.INVALID_INPUT_DATA:
            return this.invalidInputError(error.message);

          case UseCaseError.UNEXCEPTED_ERROR:
            return this.internalServerError(result.error.message, result.error);

          case UseCaseError.REPOSITORY_ERROR:
            return this.conflictError(result.error, result.error.details);

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

      const customerInvoice = <CustomerInvoice>result.object;

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