import { DomainEntity, MoneyValue, Percentage, UniqueID } from "@/core/common/domain";
import { Quantity } from "@/core/common/domain/value-objects/quantity";
import { Maybe, Result } from "@repo/rdx-utils";

export interface ICustomerInvoiceItemProps {
  description: Maybe<string>; // Descripción del artículo o servicio
  quantity: Maybe<Quantity>; // Cantidad de unidades
  unitPrice: Maybe<MoneyValue>; // Precio unitario en la moneda de la factura
  // subtotalPrice: MoneyValue; // Precio unitario * Cantidad
  discount: Maybe<Percentage>; // % descuento
  // totalPrice: MoneyValue;
}

export interface ICustomerInvoiceItem {
  description: Maybe<string>;
  quantity: Maybe<Quantity>;
  unitPrice: Maybe<MoneyValue>;
  subtotalPrice: Maybe<MoneyValue>;
  discount: Maybe<Percentage>;
  totalPrice: Maybe<MoneyValue>;

  isEmptyLine(): boolean;
}

export class CustomerInvoiceItem
  extends DomainEntity<ICustomerInvoiceItemProps>
  implements ICustomerInvoiceItem
{
  private readonly _subtotalPrice!: Maybe<MoneyValue>;
  private readonly _totalPrice!: Maybe<MoneyValue>;

  static validate(props: ICustomerInvoiceItemProps) {
    return Result.ok(props);
  }

  static create(
    props: ICustomerInvoiceItemProps,
    id?: UniqueID
  ): Result<CustomerInvoiceItem, Error> {
    const validation = CustomerInvoiceItem.validate(props);
    if (!validation.isSuccess) {
      Result.fail(new Error("Invalid invoice line data"));
    }

    return Result.ok(new CustomerInvoiceItem(props, id));
  }

  private constructor(props: ICustomerInvoiceItemProps, id?: UniqueID) {
    super(props, id);
    this._subtotalPrice = this.calculateSubtotal();
    this._totalPrice = this.calculateTotal();
  }

  isEmptyLine(): boolean {
    return this.quantity.isNone() && this.unitPrice.isNone() && this.discount.isNone();
  }

  calculateSubtotal(): Maybe<MoneyValue> {
    if (this.quantity.isNone() || this.unitPrice.isNone()) {
      return Maybe.none();
    }

    const _quantity = this.quantity.getOrUndefined()!;
    const _unitPrice = this.unitPrice.getOrUndefined()!;
    const _subtotal = _unitPrice.multiply(_quantity);

    return Maybe.some(_subtotal);
  }

  calculateTotal(): Maybe<MoneyValue> {
    const subtotal = this.calculateSubtotal();

    if (subtotal.isNone()) {
      return Maybe.none();
    }

    const _subtotal = subtotal.getOrUndefined()!;
    const _discount = this.discount.getOrUndefined()!;
    const _total = _subtotal.subtract(_subtotal.percentage(_discount));

    return Maybe.some(_total);
  }

  get description(): Maybe<string> {
    return this.props.description;
  }

  get quantity(): Maybe<Quantity> {
    return this.props.quantity;
  }

  get unitPrice(): Maybe<MoneyValue> {
    return this.props.unitPrice;
  }

  get subtotalPrice(): Maybe<MoneyValue> {
    return this._subtotalPrice;
  }

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

  get totalPrice(): Maybe<MoneyValue> {
    return this._totalPrice;
  }
}
