import { Invoice, InvoiceItem, InvoiceItemDescription } from "@/contexts/invoices/domain";
import {
  type ISequelizeMapper,
  type MapperParamsType,
  MoneyValue,
  Percentage,
  Quantity,
  Result,
  SequelizeMapper,
  UniqueID,
} from "@/core";
import { InvoiceModel } from "../sequelize";

import { InferCreationAttributes } from "sequelize";
import { InvoiceItemCreationAttributes, InvoiceItemModel } from "../sequelize";

export interface IInvoiceItemMapper
  extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}

export class InvoiceItemMapper
  extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
  implements IInvoiceItemMapper
{
  public mapToDomain(
    source: InvoiceItemModel,
    params?: MapperParamsType
  ): Result<InvoiceItem, Error> {
    const { sourceParent } = params as { sourceParent: InvoiceModel };

    const idOrError = UniqueID.create(source.item_id);

    const descriptionOrError = InvoiceItemDescription.create(source.description);

    const quantityOrError = Quantity.create({
      amount: source.quantity_amount,
      scale: source.quantity_scale,
    });

    const unitPriceOrError = MoneyValue.create({
      amount: source.unit_price_amount,
      scale: source.unit_price_scale,
      currency_code: sourceParent.invoice_currency,
    });

    const discountOrError = Percentage.create({
      amount: source.discount_amount,
      scale: source.discount_scale,
    });

    const result = Result.combine([
      idOrError,
      descriptionOrError,
      quantityOrError,
      unitPriceOrError,
      discountOrError,
    ]);

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

    return InvoiceItem.create(
      {
        description: descriptionOrError.data,
        quantity: quantityOrError.data,
        unitPrice: unitPriceOrError.data,
        discount: discountOrError.data,
      },
      idOrError.data
      //sourceParent
    );
  }

  public mapToPersistence(
    source: InvoiceItem,
    params?: MapperParamsType
  ): InferCreationAttributes<InvoiceItemModel, {}> {
    const { index, sourceParent } = params as {
      index: number;
      sourceParent: Invoice;
    };

    const lineData = {
      parent_id: undefined,
      invoice_id: sourceParent.id.toPrimitive(),
      item_type: "simple",
      position: index,

      item_id: source.id.toPrimitive(),
      description: source.description.toPrimitive(),

      quantity_amount: source.quantity.toPrimitive().amount,
      quantity_scale: source.quantity.toPrimitive().scale,

      unit_price_amount: source.unitPrice.toPrimitive().amount,
      unit_price_scale: source.unitPrice.toPrimitive().scale,

      subtotal_amount: source.subtotalPrice.toPrimitive().amount,
      subtotal_scale: source.subtotalPrice.toPrimitive().scale,

      discount_amount: source.discount.toPrimitive().amount,
      discount_scale: source.discount.toPrimitive().scale,

      total_amount: source.totalPrice.toPrimitive().amount,
      total_scale: source.totalPrice.toPrimitive().scale,
    };
    return lineData;
  }
}
