import {
  AggregateRoot,
  CurrencyData,
  ICollection,
  IDomainError,
  Language,
  MoneyValue,
  Note,
  Percentage,
  Result,
  UTCDateValue,
  UniqueID,
} from "@shared/contexts";
import { QuoteCustomer } from "./QuoteCustomer";
import { QuoteItem } from "./QuoteItem";
import { QuoteReference } from "./QuoteReference";
import { QuoteStatus } from "./QuoteStatus";

export interface IQuoteProps {
  status: QuoteStatus;
  date: UTCDateValue;
  reference: QuoteReference;
  customerReference: QuoteReference;
  customer: QuoteCustomer;
  language: Language;
  currency: CurrencyData;
  paymentMethod: Note;
  notes: Note;
  validity: Note;

  items: ICollection<QuoteItem>;

  //subtotalPrice: MoneyValue;
  discount: Percentage;
  tax: Percentage;
  //totalPrice: MoneyValue;

  dealerId: UniqueID;

  dateSent: UTCDateValue;
}

export interface IQuote {
  id: UniqueID;

  status: QuoteStatus;
  date: UTCDateValue;
  reference: QuoteReference;
  customerReference: QuoteReference;
  customer: QuoteCustomer;
  language: Language;
  currency: CurrencyData;
  paymentMethod: Note;
  notes: Note;
  validity: Note;

  subtotalPrice: MoneyValue;

  discount: Percentage;
  discountPrice: MoneyValue;

  beforeTaxPrice: MoneyValue;

  tax: Percentage;
  taxPrice: MoneyValue;

  totalPrice: MoneyValue;

  items: ICollection<QuoteItem>;

  dealerId: UniqueID;

  dateSent: UTCDateValue;
}

export class Quote extends AggregateRoot<IQuoteProps> implements IQuote {
  public static create(props: IQuoteProps, id?: UniqueID): Result<Quote, IDomainError> {
    const quote = new Quote(props, id);

    // Reglas de negocio / validaciones
    // ...
    // ...

    return Result.ok<Quote>(quote);
  }

  protected _items: ICollection<QuoteItem>;
  protected _subtotal: MoneyValue;

  protected _calculateTotalPriceItems = (): MoneyValue => {
    const result = this.props.items
      .toArray()
      .reduce<MoneyValue>(
        (accumulator, currentItem) => accumulator.add(currentItem.totalPrice),
        MoneyValue.create({ amount: 0, scale: 2, currencyCode: this.currency.code }).object
      );

    return result;
  };

  protected constructor(props: IQuoteProps, id?: UniqueID) {
    super(props, id);

    this._items = Object.freeze(props.items);
  }

  get id(): UniqueID {
    return this._id;
  }

  get date() {
    return this.props.date;
  }

  get status() {
    return this.props.status;
  }

  get reference() {
    return this.props.reference;
  }

  get customerReference() {
    return this.props.customerReference;
  }

  get customer() {
    return this.props.customer;
  }

  get language() {
    return this.props.language;
  }

  get currency() {
    return this.props.currency;
  }

  get paymentMethod() {
    return this.props.paymentMethod;
  }

  get notes() {
    return this.props.notes;
  }

  get validity() {
    return this.props.validity;
  }

  get items() {
    return this._items;
  }

  get dealerId() {
    return this.props.dealerId;
  }

  get subtotalPrice(): MoneyValue {
    if (!this._subtotal) {
      this._subtotal = this._calculateTotalPriceItems();
    }
    return this._subtotal;
  }

  get discount(): Percentage {
    return this.props.discount;
  }

  get discountPrice(): MoneyValue {
    return this.subtotalPrice.percentage(this.discount.toNumber());
  }

  get beforeTaxPrice(): MoneyValue {
    return this.subtotalPrice.subtract(this.discountPrice);
  }

  get tax(): Percentage {
    return this.props.tax;
  }

  get taxPrice(): MoneyValue {
    return this.beforeTaxPrice.percentage(this.tax.toNumber());
  }

  get totalPrice(): MoneyValue {
    return this.beforeTaxPrice.add(this.taxPrice);
  }

  get dateSent() {
    return this.props.dateSent;
  }
}
