import { ITransactionManager } from "@erp/core/api";
import { ChangeStatusCustomerInvoiceByIdRequestDTO } from "@erp/customer-invoices/common";
import { UniqueID } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { ProformaCustomerInvoiceDomainService } from "../../domain";
import { CustomerInvoiceApplicationService } from "../services";

type ChangeStatusCustomerInvoiceUseCaseInput = {
  companyId: UniqueID;
  proforma_id: string;
  dto: ChangeStatusCustomerInvoiceByIdRequestDTO;
};

export class ChangeStatusCustomerInvoiceUseCase {
  private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;

  constructor(
    private readonly service: CustomerInvoiceApplicationService,
    private readonly transactionManager: ITransactionManager
  ) {
    this.proformaDomainService = new ProformaCustomerInvoiceDomainService();
  }

  public execute(params: ChangeStatusCustomerInvoiceUseCaseInput) {
    const {
      proforma_id,
      companyId,
      dto: { new_status },
    } = params;

    const idOrError = UniqueID.create(proforma_id);
    if (idOrError.isFailure) return Result.fail(idOrError.error);

    const proformaId = idOrError.data;

    return this.transactionManager.complete(async (transaction) => {
      try {
        /** 1. Recuperamos la proforma */
        const proformaResult = await this.service.getInvoiceByIdInCompany(
          companyId,
          proformaId,
          transaction
        );
        if (proformaResult.isFailure) return Result.fail(proformaResult.error);
        const proforma = proformaResult.data;

        /** 2. Hacer el cambio de estado */
        const transitionResult = await this.proformaDomainService.transition(proforma, new_status!);
        if (transitionResult.isFailure) return Result.fail(transitionResult.error);

        const updateResult = await this.service.updateProformaStatusByIdInCompany(
          companyId,
          proformaId,
          transitionResult.data.status,
          transaction
        );
        if (updateResult.isFailure) return Result.fail(updateResult.error);

        return Result.ok();
      } catch (error: unknown) {
        return Result.fail(error as Error);
      }
    });
  }
}
