import { UniqueID, UtcDate } from "@/core/common/domain";

import {
  type IInvoiceProps,
  type IInvoiceService,
  type Invoice,
  InvoiceNumber,
  InvoiceSerie,
  InvoiceStatus,
} from "@/contexts/invoices/domain";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/logger";
import { Result } from "@repo/rdx-utils";
import { ICreateInvoiceRequestDTO } from "../presentation/dto";

export class CreateInvoiceUseCase {
  constructor(
    private readonly invoiceService: IInvoiceService,
    private readonly transactionManager: ITransactionManager
  ) {}

  public execute(
    invoiceID: UniqueID,
    dto: ICreateInvoiceRequestDTO
  ): Promise<Result<Invoice, Error>> {
    return this.transactionManager.complete(async (transaction) => {
      try {
        const validOrErrors = this.validateInvoiceData(dto);
        if (validOrErrors.isFailure) {
          return Result.fail(validOrErrors.error);
        }

        const data = validOrErrors.data;

        // Update invoice with dto
        return await this.invoiceService.createInvoice(invoiceID, data, transaction);
      } catch (error: unknown) {
        logger.error(error as Error);
        return Result.fail(error as Error);
      }
    });
  }

  private validateInvoiceData(dto: ICreateInvoiceRequestDTO): Result<IInvoiceProps, Error> {
    const errors: Error[] = [];

    const invoiceNumerOrError = InvoiceNumber.create(dto.invoice_number);
    const invoiceSeriesOrError = InvoiceSerie.create(dto.invoice_series);
    const issueDateOrError = UtcDate.create(dto.issue_date);
    const operationDateOrError = UtcDate.create(dto.operation_date);

    const result = Result.combine([
      invoiceNumerOrError,
      invoiceSeriesOrError,
      issueDateOrError,
      operationDateOrError,
    ]);

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

    const validatedData: IInvoiceProps = {
      status: InvoiceStatus.createDraft(),
      invoiceNumber: invoiceNumerOrError.data,
      invoiceSeries: invoiceSeriesOrError.data,
      issueDate: issueDateOrError.data,
      operationDate: operationDateOrError.data,
      invoiceCurrency: dto.currency,
    };

    /*if (errors.length > 0) {
      const message = errors.map((err) => err.message).toString();
      return Result.fail(new Error(message));
    }*/
    return Result.ok(validatedData);

    /*let invoice_status = InvoiceStatus.create(dto.status).object;
    if (invoice_status.isEmpty()) {
      invoice_status = InvoiceStatus.createDraft();
    }

    let invoice_series = InvoiceSeries.create(dto.invoice_series).object;
    if (invoice_series.isEmpty()) {
      invoice_series = InvoiceSeries.create(dto.invoice_series).object;
    }

    let issue_date = InvoiceDate.create(dto.issue_date).object;
    if (issue_date.isEmpty()) {
      issue_date = InvoiceDate.createCurrentDate().object;
    }

    let operation_date = InvoiceDate.create(dto.operation_date).object;
    if (operation_date.isEmpty()) {
      operation_date = InvoiceDate.createCurrentDate().object;
    }

    let invoiceCurrency = Currency.createFromCode(dto.currency).object;

    if (invoiceCurrency.isEmpty()) {
      invoiceCurrency = Currency.createDefaultCode().object;
    }

    let invoiceLanguage = Language.createFromCode(dto.language_code).object;

    if (invoiceLanguage.isEmpty()) {
      invoiceLanguage = Language.createDefaultCode().object;
    }

    const items = new Collection<InvoiceItem>(
      dto.items?.map(
        (item) =>
          InvoiceSimpleItem.create({
            description: Description.create(item.description).object,
            quantity: Quantity.create(item.quantity).object,
            unitPrice: UnitPrice.create({
              amount: item.unit_price.amount,
              currencyCode: item.unit_price.currency,
              precision: item.unit_price.precision,
            }).object,
          }).object
      )
    );

    if (!invoice_status.isDraft()) {
      throw Error("Error al crear una factura que no es borrador");
    }

    return DraftInvoice.create(
      {
        invoiceSeries: invoice_series,
        issueDate: issue_date,
        operationDate: operation_date,
        invoiceCurrency,
        language: invoiceLanguage,
        invoiceNumber: InvoiceNumber.create(undefined).object,
        //notes: Note.create(invoiceDTO.notes).object,

        //senderId: UniqueID.create(null).object,
        recipient,

        items,
      },
      invoiceId
    );*/
  }
}
