import { MoneyValue, Percentage, Quantity } from "@shared/contexts";

export const calculateQuoteTotals = (quote: any, force: boolean = false) => {
  const { discount: discount_dto, tax: tax_dto, subtotal_price: subtotal_price_dto } = quote || {};

  const discountOrError = Percentage.create(
    discount_dto || {
      amount: null,
      scale: 2,
    }
  );

  if (discountOrError.isFailure) {
    throw discountOrError.error;
  }
  const discount = discountOrError.object;

  const taxOrError = Percentage.create(
    tax_dto || {
      amount: null,
      scale: 2,
    }
  );

  if (taxOrError.isFailure) {
    throw taxOrError.error;
  }
  const tax = taxOrError.object;

  const subtotalOrError = MoneyValue.create(
    subtotal_price_dto || {
      amount: null,
      scale: 2,
    }
  );

  if (subtotalOrError.isFailure) {
    throw subtotalOrError.error;
  }
  const subtotalPrice = force
    ? calculateQuoteItemsTotals(quote.items).convertScale(2)
    : subtotalOrError.object;

  const discountPrice = subtotalPrice.percentage(discount.toNumber()).convertScale(2);

  const priceBeforeTaxes = subtotalPrice.subtract(discountPrice).convertScale(2);

  const taxesPrice = priceBeforeTaxes.percentage(tax.toNumber()).convertScale(2);

  const totalPrice = priceBeforeTaxes.add(taxesPrice).convertScale(2);

  return {
    subtotalPrice,
    discount: quote.discount,
    discountPrice,
    priceBeforeTaxes,
    tax,
    taxesPrice,
    totalPrice,
  };
};

export const calculateQuoteItemsTotals = (items: any[]) => {
  let totalPrice = MoneyValue.create({
    amount: 0,
    scale: 2,
  }).object;

  items &&
    items.map((item: any) => {
      const quoteItemTotals = calculateQuoteItemTotals(item);
      totalPrice = totalPrice.add(quoteItemTotals.totalPrice);
    });

  return totalPrice;
};

export const calculateQuoteItemTotals = (item: any) => {
  const { quantity: quantity_dto, unit_price: unit_price_dto, discount: discount_dto } = item || {};

  if (
    (quantity_dto && quantity_dto.amount === null) ||
    (unit_price_dto && unit_price_dto.amount === null)
  ) {
    return {
      quantity: Quantity.create({
        amount: quantity_dto.amount,
        scale: 0,
      }).object,
      unitPrice: MoneyValue.create({
        amount: unit_price_dto.amount,
        scale: 2,
      }).object,
      subtotalPrice: MoneyValue.create({
        amount: null,
        scale: 2,
      }).object,
      discount: Percentage.create({
        amount: discount_dto.amount,
        scale: 2,
      }).object,
      totalPrice: MoneyValue.create({
        amount: null,
        scale: 2,
      }).object,
    };
  }

  const quantityOrError = Quantity.create(quantity_dto);
  if (quantityOrError.isFailure) {
    throw quantityOrError.error;
  }
  const quantity = quantityOrError.object;

  const unitPriceOrError = MoneyValue.create(unit_price_dto);
  if (unitPriceOrError.isFailure) {
    throw unitPriceOrError.error;
  }
  const unitPrice = unitPriceOrError.object;

  const discountOrError = Percentage.create(discount_dto);
  if (discountOrError.isFailure) {
    throw discountOrError.error;
  }
  const discount = discountOrError.object;

  const subtotalPrice = unitPrice.multiply(quantity.toNumber());
  const totalPrice = subtotalPrice.subtract(subtotalPrice.percentage(discount.toNumber()));

  return {
    quantity,
    unitPrice,
    subtotalPrice,
    discount,
    totalPrice,
  };
};
