import {
  bifurcateInclusive,
  type TaxSlabSnapshotInput,
} from './tax-bifurcation.helper';

/**
 * Pricing-bifurcation helper — turns a pricing row's inclusive totals
 * into base + tax_amount per cell using the bifurcation math from
 * `tax-bifurcation.helper`.
 *
 * Used by transport-pricing and activity-pricing services on
 * create / update / bulk / Excel import. Existing inclusive `*_price`
 * columns stay as the entered value; new `*_base_price` and
 * `*_tax_amount` are derived from each on save. Reads switch to the
 * new columns gradually.
 *
 * Symmetry: the same 10 price cells live on both sides of the matrix
 * (sell + floor) — this helper picks ONE side, fed by the caller.
 *
 *   Sell side:
 *     default_price        → default_base_price        + default_tax_amount
 *     season_1_price       → season_1_base_price       + season_1_tax_amount
 *     ...
 *     season_4_price       → season_4_base_price       + season_4_tax_amount
 *
 *   Floor side (prefix every column with `floor_`):
 *     floor_default_price  → floor_default_base_price  + floor_default_tax_amount
 *     floor_season_1_price → floor_season_1_base_price + floor_season_1_tax_amount
 *     ...
 *
 * The migration (1781100000000) only added columns for default + 4
 * seasons. If the pricing schema ever extends to a 5th season, this
 * helper picks it up by adding the field name to the relevant tier
 * array below — no other call site needs to change.
 *
 * Rounding step: stored on `currencies.rounding` (int). Caller passes
 * it through; this helper doesn't reach into the DB itself so it
 * stays unit-testable.
 *
 * Null behaviour: a null inclusive cell stays null on both derived
 * columns. Saves through the existing whitelist mechanism (services'
 * pickPrices) skip undefined keys entirely.
 */

const PRICE_TIERS = ['default', 'season_1', 'season_2', 'season_3', 'season_4'] as const;
type Tier = (typeof PRICE_TIERS)[number];

/** Names of the inclusive `*_price` source columns on the sell side. */
export const SELL_PRICE_FIELDS = PRICE_TIERS.map((t) => `${t}_price` as const);

/** Names of the inclusive `floor_*_price` source columns on the floor side. */
export const FLOOR_PRICE_FIELDS = PRICE_TIERS.map((t) => `floor_${t}_price` as const);

export type SellPriceField = (typeof SELL_PRICE_FIELDS)[number];
export type FloorPriceField = (typeof FLOOR_PRICE_FIELDS)[number];

/**
 * Returns the `*_base_price` / `*_tax_amount` derived from each
 * inclusive cell present in `prices`. Cells whose value is null or
 * undefined are echoed as null on the derived columns (so an
 * "intentionally cleared" cell clears its bifurcation too).
 */
export function bifurcatePricingRow(
  prices: Record<string, unknown>,
  slab: TaxSlabSnapshotInput | null,
  rounding: number,
  side: 'sell' | 'floor',
): Record<string, number | null> {
  const out: Record<string, number | null> = {};
  const fields: readonly string[] = side === 'sell' ? SELL_PRICE_FIELDS : FLOOR_PRICE_FIELDS;

  for (const field of fields) {
    const v = prices[field];
    // Tier name is the field minus the trailing `_price` (and the
    // optional `floor_` prefix). Stripped here once so the output keys
    // match what the migration created on the table.
    const tier: Tier = (side === 'sell'
      ? field.replace(/_price$/, '')
      : field.replace(/^floor_/, '').replace(/_price$/, '')) as Tier;

    const baseKey = side === 'sell' ? `${tier}_base_price` : `floor_${tier}_base_price`;
    const taxKey = side === 'sell' ? `${tier}_tax_amount` : `floor_${tier}_tax_amount`;

    if (v == null || v === '') {
      // Clear both derived columns when the inclusive cell is unset.
      // Don't leave stale base/tax around from a previous save that
      // had a value here.
      out[baseKey] = null;
      out[taxKey] = null;
      continue;
    }
    const total = Number(v);
    if (!Number.isFinite(total)) {
      out[baseKey] = null;
      out[taxKey] = null;
      continue;
    }
    const result = bifurcateInclusive(total, slab, rounding);
    out[baseKey] = result.base;
    out[taxKey] = result.tax_amount;
  }
  return out;
}

/**
 * Bifurcates BOTH sides at once — convenience wrapper that takes the
 * full pricing payload (sell + floor cells) and emits the full set of
 * derived columns. Caller passes the same slab + rounding because
 * floor and sell share the destination's effective slab.
 */
export function bifurcatePricingRowBoth(
  prices: Record<string, unknown>,
  slab: TaxSlabSnapshotInput | null,
  rounding: number,
): Record<string, number | null> {
  return {
    ...bifurcatePricingRow(prices, slab, rounding, 'sell'),
    ...bifurcatePricingRow(prices, slab, rounding, 'floor'),
  };
}
