import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@/core/common/domain";
import { Collection, Result } from "@repo/rdx-utils";
import { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities";
import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects";

export interface IInvoiceProps {
  invoiceNumber: InvoiceNumber;
  invoiceSeries: InvoiceSerie;

  status: InvoiceStatus;

  issueDate: UtcDate;
  operationDate: UtcDate;

  //dueDate: UtcDate; // ? --> depende de la forma de pago

  //tax: Tax; // ? --> detalles?
  invoiceCurrency: string;

  //language: Language;

  //purchareOrderNumber: string;
  //notes: Note;

  //senderId: UniqueID;

  //paymentInstructions: Note;
  //paymentTerms: string;

  customer?: InvoiceCustomer;
  items?: InvoiceItems;
}

export interface IInvoice {
  id: UniqueID;
  invoiceNumber: InvoiceNumber;
  invoiceSeries: InvoiceSerie;

  status: InvoiceStatus;

  issueDate: UtcDate;
  operationDate: UtcDate;

  //senderId: UniqueID;

  customer?: InvoiceCustomer;

  //dueDate

  //tax: Tax;
  //language: Language;
  invoiceCurrency: string;

  //purchareOrderNumber: string;
  //notes: Note;

  //paymentInstructions: Note;
  //paymentTerms: string;

  items: InvoiceItems;

  calculateSubtotal: () => MoneyValue;
  calculateTaxTotal: () => MoneyValue;
  calculateTotal: () => MoneyValue;
}

export class Invoice extends AggregateRoot<IInvoiceProps> implements IInvoice {
  private _items!: Collection<InvoiceItem>;
  //protected _status: InvoiceStatus;

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

    this._items = props.items || InvoiceItems.create();
  }

  static create(props: IInvoiceProps, id?: UniqueID): Result<Invoice, Error> {
    const invoice = new Invoice(props, id);

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

    // 🔹 Disparar evento de dominio "InvoiceAuthenticatedEvent"
    //const { invoice } = props;
    //user.addDomainEvent(new InvoiceAuthenticatedEvent(id, invoice.toString()));

    return Result.ok(invoice);
  }

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

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

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

  /*get senderId(): UniqueID {
    return this.props.senderId;
  }*/

  get customer(): InvoiceCustomer | undefined {
    return this.props.customer;
  }

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

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

  get dueDate() {
    return undefined;
  }

  get tax() {
    return undefined;
  }

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

  get items() {
    return this._items;
  }

  /*get purchareOrderNumber() {
    return this.props.purchareOrderNumber;
  }

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

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

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

  get shipTo() {
    return this.props.shipTo;
  }*/

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

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

  // Method to get the complete list of line items
  /*get lineItems(): InvoiceLineItem[] {
    return this._lineItems;
  }

  addLineItem(lineItem: InvoiceLineItem, position?: number): void {
    if (position === undefined) {
      this._lineItems.push(lineItem);
    } else {
      this._lineItems.splice(position, 0, lineItem);
    }
  }*/

  calculateSubtotal(): MoneyValue {
    const invoiceSubtotal = MoneyValue.create({
      amount: 0,
      currency_code: this.props.invoiceCurrency,
      scale: 2,
    }).data;

    return this._items.getAll().reduce((subtotal, item) => {
      return subtotal.add(item.calculateTotal());
    }, invoiceSubtotal);
  }

  // Method to calculate the total tax in the invoice
  calculateTaxTotal(): MoneyValue {
    const taxTotal = MoneyValue.create({
      amount: 0,
      currency_code: this.props.invoiceCurrency,
      scale: 2,
    }).data;

    return taxTotal;
  }

  // Method to calculate the total invoice amount, including taxes
  calculateTotal(): MoneyValue {
    return this.calculateSubtotal().add(this.calculateTaxTotal());
  }
}
