import { EntityNotFoundError, ITransactionManager } from "@erp/core/api";
import { UniqueID } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { CustomerInvoiceApplicationService, CustomerInvoiceNumber } from "../../domain";
import { StatusInvoiceIsApprovedSpecification } from "../specs";

type IssueCustomerInvoiceUseCaseInput = {
  companyId: UniqueID;
  invoice_id: string;
};

export class IssueCustomerInvoiceUseCase {
  constructor(
    private readonly service: CustomerInvoiceApplicationService,
    private readonly transactionManager: ITransactionManager
  ) {}

  public execute(params: IssueCustomerInvoiceUseCaseInput) {
    const { invoice_id, companyId } = params;

    const idOrError = UniqueID.create(invoice_id);

    if (idOrError.isFailure) {
      return Result.fail(idOrError.error);
    }

    const invoiceId = idOrError.data;

    return this.transactionManager.complete(async (transaction) => {
      try {
        const invoiceResult = await this.service.getInvoiceByIdInCompany(
          companyId,
          invoiceId,
          transaction
        );

        if (invoiceResult.isFailure) {
          return Result.fail(invoiceResult.error);
        }

        const invoiceProforma = invoiceResult.data;

        const isOk = new StatusInvoiceIsApprovedSpecification().isSatisfiedBy(invoiceProforma);

        if (!isOk) {
          return Result.fail(
            new EntityNotFoundError("Customer invoice", "id", invoiceId.toString())
          );
        }

        // La factura se puede emitir.
        // Pedir el número de factura
        const newInvoiceNumber = CustomerInvoiceNumber.create("xxx/001").data;

        // Asignamos el número de la factura

        const issuedInvoiceResult = invoiceProforma.issueInvoice(newInvoiceNumber);
        if (issuedInvoiceResult.isFailure) {
          return Result.fail(new EntityNotFoundError("Customer invoice", "id", error));
        }

        const issuedInvoice = issuedInvoiceResult.data;

        this.service.saveInvoice(issuedInvoice, transaction);

        //return await this.service.IssueInvoiceByIdInCompany(companyId, invoiceId, transaction);
      } catch (error: unknown) {
        return Result.fail(error as Error);
      }
    });
  }
}
