/**
 * Core sales calculation library by Softseti
 * @module softseti-sale-calculator-library
 */

import { PaymentCalculation, RefundCalculation, RefundOptions, Sale, SaleItem, SaleTotals, WholesaleLevel } from "./models/interfaces";

declare module 'softseti-sale-calculator-library' {

  /** One rule evaluation captured while applying taxes. */
  export interface RuleTrackingEntry {
    trigger: string;
    rule_id: string | null;
    rule_name: string | null;
    tax_id: string | number | null;
    tax_abbreviation: string | null;
    product_id: string | number | null;
    evaluated: boolean;
    success: boolean;
    applied: boolean;
    original_rate: number | null;
    adjusted_rate: number | null;
    error: string | null;
  }

  // SALE CALCULATOR

  /**
   * Initializes the calculator with global parameters
   * @param {object} params - Configuration parameters
   */
  export function init(params: any, dependecies?: any): void;

  /**
   * Preprocesses sale data for calculations
   * @param {Sale} sale - Sale object to preprocess
   * @returns {Promise<Sale>} Preprocessed sale object
   */
  export function preprocessSale(sale: any): Promise<any>;

  /**
   * Calculates subtotal for a sale
   * @param {Sale} sale - Sale object
   * @returns {number} Subtotal amount
   */
  export function calcSubtotal(sale: any): number;

  /**
   * Calculates total amount for a sale
   * @param {Sale} sale - Sale object
   * @returns {Promise<number>} Total amount
   */
  export function calcTotal(sale: any): Promise<number>;

  /**
   * Calculates remaining debt for a sale
   * @param {Sale} sale - Sale object
   * @returns {Promise<number>} Debt amount
   */
  export function calcDebt(sale: any): Promise<number>;

  /**
   * Calculates change amount for a sale
   * @param {Sale} sale - Sale object
   * @returns {Promise<number>} Change amount
   */
  export function calcChange(sale: any): Promise<number>;

  /**
   * Calculates taxes by tax abbreviation
   * @param {Sale} sale - Sale object
   * @param {string} abbreviation - Tax abbreviation (e.g., 'VAT')
   * @returns {number} Tax amount
   */
  export function calcTaxesByAbbreviation(sale: Sale, abbreviation: string): number;

  /**
   * Calculates original payment amount
   * @param {object} payment - Payment object
   * @param {Sale} sale - Sale object
   * @returns {Promise<number>} Original payment amount
   */
  export function calcOriginalPaymentAmount(payment: any, sale: Sale): Promise<number>;

  /**
   * Calculates given payment amount
   * @param {object} payment - Payment object
   * @param {Sale} sale - Sale object
   * @returns {number} Given payment amount
   */
  export function calcGivedPaymentAmount(payment: any, sale: Sale): number;

  /**
   * Calculates detailed payment information
   * @param {object} payment - Payment object
   * @param {Sale} sale - Sale object
   * @returns {Promise<PaymentCalculation>} Payment details
   */
  export function calculatePaymentDetails(payment: any, sale: Sale): Promise<PaymentCalculation>;

  /**
   * Calculates sale product price including wholesale levels and currency conversion
   * @param {object} saleProduct - Sale product object
   * @param {object} sale - Sale object
   * @returns {number} Product price
   */
  export function calcDwSaleProductPrice(saleProduct: any, sale: any): number;
  /**
   * Gets applied wholesale levels for all products in a sale
   * @param {Sale} sale - Sale object
   * @returns {WholesaleLevel[]} Applied wholesale levels
   */
  export function appliedWholesaleLevels(sale: any): WholesaleLevel[];

  /**
   * Calculates all applicable taxes for the sale and returns them in API format
   * @param {object} sale - Sale object
   * @returns {Promise<Array>} Array of tax objects with id, abbreviation, and amount
   */
  export function getApplicableDwTaxes(sale: any): Promise<any[]>;

  /**
   * Returns the per-calculation rule trace: for each rule evaluated while
   * applying taxes, whether it ran ok, whether it was applied and the rate it
   * produced. Reset on each init(); read after the tax calculation.
   * @returns {RuleTrackingEntry[]} Rule trace
   */
  export function getRuleTracking(): RuleTrackingEntry[];

  /**
   * Gets consolidated taxes by merging taxes with same id, abbreviation and rate
   * @param {object} sale - Sale data object
   * @returns {Array} Array of unified tax objects with id, abbreviation, rate and total amount
   */
  export function getConsolidatedTaxes(sale: any): any[];

  /**
   * Calculates comprehensive sale totals
   * @param {Sale} sale - Sale object
   * @returns {Promise<SaleTotals>} Sale totals
   */
  export function calculateSaleTotals(sale: any): Promise<SaleTotals>;

  /**
   * Internal sale calculation methods (advanced use only)
   */
  export const _internals: {
    /** Calculates sale product line sum @internal */
    calcDwSaleProductSum: (saleProduct: any, sale: Sale) => number;
    /** Calculates sale product discount @internal */
    calcDwSaleProductDiscount: (product: any, sale: Sale) => number;
    /** Gets applicable product taxes @internal */
    getApplicableProductTaxes: (saleProduct: any, productSum: number, sale: Sale) => Promise<number>;
    /** Currency exchange calculation @internal */
    exchange: (amount: number, fromCurrency: string, toCurrency: string) => number;
    /** Loaded currency catalog indexed by id (readonly view) @internal */
    readonly currencies: Record<number | string, { id: number; iso: string }>;
  };

  /**
   * Calculates refund details for a sale
   * @param {Sale} sale - Original sale object
   * @param {SaleItem[]} returnItems - Items to return with quantity or refund amount
   * @param {RefundOptions} options - Refund calculation options
   * @param {string|number} [currentMemoId] - Current credit memo ID (for partial refunds)
   * @example
   * // Full item refund
   * calculateRefund(sale, returnItems, {
   *   input_type: 'items_full_refund',
   *   decimal_precision: 2
   * });
   * @example
   * // Amount-only refund
   * calculateRefund(sale, [], {
   *   input_type: 'amount_only',
   *   requested_refund_amount: 500,
   *   decimal_precision: 2
   * });
   * @returns {RefundCalculation} Refund calculation results
   */
  export function calculateRefund(
    sale: Sale,
    returnItems: SaleItem[],
    options: RefundOptions,
    currentMemoId?: string | number
  ): RefundCalculation;

  // PURCHASE CALCULATOR

  /**
   * Purchase calculation module.
   * Unlike the sale calculator, products are NOT indexed —
   * cost and taxes are read directly from each dwPurchaseProduct entry.
   *
   * @example
   * import { purchase } from 'softseti-sale-calculator-library';
   *
   * const { subtotal, total, taxLines } = await purchase.calculatePurchaseTotals({
   *   company_id: 1,
   *   branch_id: 1,
   *   currency_iso: 'MXN',
   *   dwPurchaseProducts: [
   *     { product_id: 1, quantity: 2, cost: 500, taxes: [{ tax_id: 7, abbreviation: 'IVA', rate: 16 }] }
   *   ],
   *   generalTaxes: [{ tax_id: 138, abbreviation: 'IPSP', rate: 10 }]
   * });
   */
  export const purchase: {

    /**
     * Initializes the purchase calculator with exchange rates and settings.
     * @param {object} params - exchange_rates, currency_converter_rates, businessRules, decimal_places, use_rounding, rules_apply
     * @param {object} dependencies - zenEngine (optional)
     */
    init(params: any, dependencies?: any): void;

    /**
     * Calculates the purchase subtotal (sum of all product lines before taxes).
     * cost must already be in the purchase document currency.
     * @param {object} purchase - Purchase object containing dwPurchaseProducts
     * @returns {number} Subtotal in purchase currency
     */
    calcSubtotal(purchase: any): number;

    /**
     * Calculates the purchase total including all applicable taxes.
     * Product-specific taxes are applied per line; general taxes over the full subtotal.
     * @param {object} purchase - Purchase object
     * @returns {Promise<number>} Total in purchase currency
     */
    calcTotal(purchase: any): Promise<number>;

    /**
     * Main entry point. Calculates subtotal, total and taxLines in a single call.
     * @param {object} purchase - Purchase object containing:
     *   - company_id {number}
     *   - branch_id {number}
     *   - currency_iso {string}
     *   - dwPurchaseProducts: Array<{ product_id, quantity, cost, taxes[] }>
     *   - generalTaxes: DwPurchaseTax[] (optional)
     * @returns {Promise<{ subtotal: number, total: number, taxLines: PurchaseTaxLine[] }>}
     */
    calculatePurchaseTotals(purchase: any): Promise<{
      subtotal: number;
      total: number;
      taxLines: Array<{
        id: number | null;
        abbreviation: string;
        rate: number;
        amount: number;
        is_general: boolean;
      }>;
    }>;

    /**
     * Returns all taxes consolidated by key, respecting RuleEngine adjustments.
     * Output is consistent with calcTotal. Used to build taxLines in the UI summary.
     * @param {object} purchase - Purchase object
     * @returns {Promise<Array>} Consolidated tax lines
     */
    getConsolidatedTaxes(purchase: any): Promise<Array<{
      id: number | null;
      abbreviation: string;
      rate: number;
      amount: number;
      is_general: boolean;
    }>>;

    /** Internal purchase calculation methods (advanced use only) */
    _internals: {
      /** Calculates product line sum: quantity * cost @internal */
      calcProductLineSum(purchaseProduct: any): number;
      /** Gets applicable taxes for a single product line @internal */
      getApplicableProductTaxes(purchaseProduct: any, lineSum: number, purchase: any): Promise<number>;
      /** Calculates general taxes amount over the full subtotal @internal */
      calcGeneralTaxesAmount(purchase: any, subtotal: number): Promise<number>;
      /** Currency exchange calculation @internal */
      exchange(amount: number, fromCurrency: string, toCurrency: string): number;
      /** Rounds or truncates a currency value @internal */
      roundCurrency(value: number, overrideRounding?: boolean): number;
    };
  };
}
