import type { StaleSplit } from '@platform-modules/commerce-checkout'
import { CheckoutWireError } from './errors.js'

function asObject(v: unknown, ctx: string): Record<string, unknown> {
  if (typeof v !== 'object' || v === null) {
    throw new CheckoutWireError(`${ctx}: expected an object, got ${v === null ? 'null' : typeof v}`)
  }
  return v as Record<string, unknown>
}

// One revival convention shared across the -react siblings.
function reviveAmount(v: unknown, ctx: string): bigint {
  if (typeof v === 'bigint') return v
  if (typeof v === 'number') {
    if (!Number.isSafeInteger(v)) {
      throw new CheckoutWireError(`${ctx}: amount must be a safe-integer minor-unit value (values ≥ 2^53 must be string-encoded), got ${v}`)
    }
    return BigInt(v)
  }
  if (typeof v === 'string') {
    if (v.length > 22) {
      throw new CheckoutWireError(`${ctx}: amount string exceeds 21 digits (length ${v.length})`)
    }
    if (!/^-?\d{1,21}$/.test(v)) throw new CheckoutWireError(`${ctx}: amount is not a valid integer minor-unit string (≤21 digits): ${JSON.stringify(v)}`)
    return BigInt(v)
  }
  throw new CheckoutWireError(`${ctx}: amount missing or wrong type (${typeof v})`)
}

/** Wire JSON (409 stale body) → typed StaleSplit. The ONE revive helper. §3 */
export function reviveStaleSplit(raw: unknown): StaleSplit {
  const r = asObject(raw, 'reviveStaleSplit')
  if (!Array.isArray(r.removed) || r.removed.some((x) => typeof x !== 'string')) {
    throw new CheckoutWireError('reviveStaleSplit: removed must be a string[]')
  }
  if (!Array.isArray(r.updated)) {
    throw new CheckoutWireError('reviveStaleSplit: updated must be an array')
  }
  return {
    removed: r.removed as string[],
    updated: r.updated.map((u, i) => {
      const o = asObject(u, `reviveStaleSplit: updated[${i}]`)
      if (typeof o.variantId !== 'string') {
        throw new CheckoutWireError(`reviveStaleSplit: updated[${i}].variantId must be a string`)
      }
      return {
        variantId: o.variantId,
        was: reviveAmount(o.was, `reviveStaleSplit: updated[${i}].was`),
        now: reviveAmount(o.now, `reviveStaleSplit: updated[${i}].now`),
      }
    }),
  }
}