import { JsonTaxCatalogProvider } from "@erp/core";
import {
  ISequelizeDomainMapper,
  MapperParamsType,
  SequelizeDomainMapper,
  Tax,
} from "@erp/core/api";

import {
  UniqueID,
  ValidationErrorCollection,
  ValidationErrorDetail,
  extractOrPushError,
} from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { CustomerInvoiceItem } from "../../../domain";
import {
  CustomerInvoiceItemTaxCreationAttributes,
  CustomerInvoiceItemTaxModel,
} from "../../sequelize";

export interface IItemTaxesDomainMapper
  extends ISequelizeDomainMapper<
    CustomerInvoiceItemTaxModel,
    CustomerInvoiceItemTaxCreationAttributes,
    Tax
  > {}

export class ItemTaxesDomainMapper
  extends SequelizeDomainMapper<
    CustomerInvoiceItemTaxModel,
    CustomerInvoiceItemTaxCreationAttributes,
    Tax
  >
  implements IItemTaxesDomainMapper
{
  private _taxCatalog!: JsonTaxCatalogProvider;

  constructor(params: MapperParamsType) {
    super();
    const { taxCatalog } = params as {
      taxCatalog: JsonTaxCatalogProvider;
    };

    if (!taxCatalog) {
      throw new Error('taxCatalog not defined ("ItemTaxesMapper")');
    }

    this._taxCatalog = taxCatalog;
  }

  public mapToDomain(
    source: CustomerInvoiceItemTaxModel,
    params?: MapperParamsType
  ): Result<Tax, Error> {
    const { errors, index } = params as {
      index: number;
      errors: ValidationErrorDetail[];
    };

    const tax = extractOrPushError(
      Tax.createFromCode(source.tax_code, this._taxCatalog),
      `taxes[${index}].tax_code`,
      errors
    );

    // Creación del objeto de dominio
    const createResult = Tax.create(tax!);
    if (createResult.isFailure) {
      return Result.fail(
        new ValidationErrorCollection("Invoice item tax creation failed", [
          { path: `taxes[${index}]`, message: createResult.error.message },
        ])
      );
    }

    return createResult;
  }

  public mapToPersistence(
    source: Tax,
    params?: MapperParamsType
  ): Result<CustomerInvoiceItemTaxCreationAttributes, Error> {
    const { errors, parent } = params as {
      parent: CustomerInvoiceItem;
      errors: ValidationErrorDetail[];
    };

    const taxableAmount = parent.getTaxableAmount();
    const taxAmount = taxableAmount.percentage(source.percentage);

    return Result.ok({
      tax_id: UniqueID.generateNewID().toPrimitive(),
      item_id: parent.id.toPrimitive(),

      tax_code: source.code,

      taxable_amount_value: taxableAmount.value,
      taxable_amount_scale: taxableAmount.scale,

      taxes_amount_value: taxAmount.value,
      taxes_amount_scale: taxAmount.scale,
    });
  }
}
