import { ArticleIdentifier } from "@/contexts/catalog/domain";
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
import { Description, MoneyValue, Percentage, Quantity, UniqueID } from "@shared/contexts";
import { IQuoteItemProps, Quote, QuoteItem } from "../../domain";
import { ISalesContext } from "../Sales.context";
import { Quote_Model } from "../sequelize";
import { QuoteItemCreationAttributes, QuoteItem_Model } from "../sequelize/quoteItem.model";

export interface IQuoteItemMapper
  extends ISequelizeMapper<QuoteItem_Model, QuoteItemCreationAttributes, QuoteItem> {}

export const createQuoteItemMapper = (context: ISalesContext): IQuoteItemMapper =>
  new QuoteItemMapper({ context });

class QuoteItemMapper
  extends SequelizeMapper<QuoteItem_Model, QuoteItemCreationAttributes, QuoteItem>
  implements IQuoteItemMapper
{
  protected toDomainMappingImpl(
    source: QuoteItem_Model,
    params: { sourceParent: Quote_Model }
  ): QuoteItem {
    const { sourceParent } = params;
    const id = this.mapsValue(source, "item_id", UniqueID.create);

    const idArticle = this.mapsValue(source, "id_article", ArticleIdentifier.create);

    const props: IQuoteItemProps = {
      idArticle,
      description: this.mapsValue(source, "description", Description.create),
      quantity: this.mapsValue(source, "quantity", (quantity) =>
        Quantity.create({
          amount: quantity,
          scale: 2,
        })
      ),
      unitPrice: this.mapsValue(source, "unit_price", (unit_price) =>
        MoneyValue.create({
          amount: unit_price,
          currencyCode: sourceParent.currency_code,
          scale: 2,
        })
      ),

      /*subtotalPrice: this.mapsValue(source, "subtotal_price", (subtotal_price) =>
        MoneyValue.create({
          amount: subtotal_price,
          currencyCode: sourceParent.currency_code,
          scale: 2,
        })
      ),
      */

      discount: this.mapsValue(source, "discount", (discount) =>
        Percentage.create({
          amount: discount,
          scale: 2,
        })
      ),

      /*totalPrice: this.mapsValue(source, "total_price", (total_price) =>
        MoneyValue.create({
          amount: total_price,
          currencyCode: sourceParent.currency_code,
          scale: 2,
        })
      ),*/
    };

    const quoteItemOrError = QuoteItem.create(props, id);

    if (quoteItemOrError.isFailure) {
      throw quoteItemOrError.error;
    }

    return quoteItemOrError.object;
  }

  protected toPersistenceMappingImpl(
    source: QuoteItem,
    params: { index: number; sourceParent: Quote }
  ): QuoteItemCreationAttributes {
    const { index, sourceParent } = params;

    return {
      item_id: source.id.toString(),
      quote_id: sourceParent.id.toPrimitive(),
      position: index,
      id_article: source.idArticle.toPrimitive(),
      description: source.description.toPrimitive(),
      quantity: source.quantity.convertScale(2).toPrimitive(),
      unit_price: source.unitPrice.convertScale(2).toPrimitive(),
      subtotal_price: source.subtotalPrice.convertScale(2).toPrimitive(),
      discount: source.discount.convertScale(2).toPrimitive(),
      total_price: source.totalPrice.convertScale(2).toPrimitive(),
    };
  }
}
