import { Seam } from '../seam.js'
import { type ActorContext } from '../db/actor.js'

/**
 * The entitlement assertion helper. Required by #20 decision 3.
 *
 * Entitlement is resolved once into actor context and asserted per feature at
 * each feature's own entry — not as row visibility, and not at one chokepoint.
 * Writing a document is free; writing it FOR REUSE is paid. The same INSERT
 * serves both, so an operation deny-list would have to encode intent it
 * cannot see.
 *
 * ── THE GOVERNING PRINCIPLE ─────────────────────────────────────────────
 *
 *   Entitlement gates what a vendor may newly undertake,
 *   never what a retailer has already come to rely on.
 *
 * Restated by #34 when the free tier was removed. Concretely: expiry state is
 * computed for every vendor regardless of billing; eligibility never depends
 * on subscription state; and on lapse, live participations run to completion.
 * ────────────────────────────────────────────────────────────────────────
 *
 * Useful side effect: the call sites of `require` ARE the paid-feature list.
 * The pricing page is derived from the code rather than maintained alongside it.
 */
export type Feature =
  | 'ai.draft'
  | 'ai.matching'
  | 'ai.go_no_go'
  | 'ai.response_completeness'
  | 'integration.api'
  | 'sso'

export const FEATURE_TIER: Record<Feature, 'base' | 'pro' | 'enterprise'> = {
  'ai.draft': 'pro',
  'ai.matching': 'pro',
  'ai.go_no_go': 'pro',
  'ai.response_completeness': 'pro',
  'integration.api': 'enterprise',
  sso: 'enterprise',
}

export interface Entitled extends ActorContext {
  tier: 'base' | 'pro' | 'enterprise'
  lapsed: boolean
}

export class NotEntitled extends Error {
  constructor(readonly feature: Feature, readonly required: string) {
    super(`${feature} requires ${required}`)
    this.name = 'NotEntitled'
  }
}

/**
 * Assert at a feature entry. Throwing is the API — a missing entitlement is
 * never a silent empty result, because that is what RLS denial looks like and
 * the two must stay distinguishable.
 */
export function require(ctx: Entitled, feature: Feature): void {
  throw new Seam('#35', `entitlement resolution for ${feature} (${ctx.tier})`)
}

/**
 * Visible-but-locked is the DEFAULT rendering for a missing entitlement.
 * Absent is a bug — Pro has no upgrade moment if the affordance is invisible
 * (#34, carried into #23).
 */
export function affordance(ctx: Entitled, feature: Feature): 'enabled' | 'locked' {
  return ctx.tier === FEATURE_TIER[feature] || ctx.tier === 'enterprise' ? 'enabled' : 'locked'
}
