import { z } from 'zod'
import { defineDomainRecord } from '../helpers'

// ---------------------------------------------------------------------------
// Pricing model — the four canonical pricing structures used in B2B SaaS and
// professional services. "custom" covers bespoke / negotiated pricing.
// ---------------------------------------------------------------------------

export const PricingModelSchema = z
  .enum(['one-time', 'subscription', 'usage-based', 'custom'])
  .meta({ label: 'Pricing model', color: 'green' })

// ---------------------------------------------------------------------------
// Product schema — one entry per distinct offering (product or service).
// Modeled after Business Model Canvas "Value Propositions" and company profile
// product/service catalog language. Fields use plain English throughout.
// ---------------------------------------------------------------------------

export const ProductSchema = z.object({
  /** Stable unique identifier for the product (e.g. "product-starter-plan"). */
  id: z.string().trim().min(1).max(100),
  /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
  order: z.number(),
  /** Human-readable name shown to agents and in UI (e.g. "Starter Plan"). */
  name: z.string().trim().max(200).default(''),
  /** One or two sentences describing what this product/service delivers. */
  description: z.string().trim().max(2000).default(''),
  /**
   * How this product is priced:
   * - "one-time" — single purchase (setup fee, project fee)
   * - "subscription" — recurring (monthly/annual SaaS, retainer)
   * - "usage-based" — metered by consumption (API calls, seats)
   * - "custom" — negotiated or bespoke pricing
   */
  pricingModel: PricingModelSchema.default('custom'),
  /** Base price amount (≥ 0). Currency unit defined by `currency`. */
  price: z.number().min(0).default(0),
  /**
   * ISO 4217 currency code (e.g. "USD", "EUR", "GBP").
   * Free-form string to accommodate any currency; defaults to "USD".
   */
  currency: z.string().trim().max(10).default('USD'),
  /**
   * IDs of customer segments this product targets.
   * Each id must reference a declared `customers.segments[].id`.
   * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
   */
  targetSegmentIds: z.array(z.string().trim().min(1)).default([]),
  /**
   * Optional: ID of the platform system responsible for delivering this product.
   * When present, must reference a declared `systems.systems[].id`.
   * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
   */
  deliveryFeatureId: z.string().trim().min(1).optional()
})

// ---------------------------------------------------------------------------
// Offerings domain schema — id-keyed map of products and services.
// ---------------------------------------------------------------------------

export const OfferingsDomainSchema = z
  .record(z.string(), ProductSchema)
  .refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
    message: 'Each product entry id must match its map key'
  })
  .default({})

// ---------------------------------------------------------------------------
// Seed — empty by default; adapters populate with real product definitions.
// ---------------------------------------------------------------------------

export const DEFAULT_ORGANIZATION_MODEL_OFFERINGS: z.infer<typeof OfferingsDomainSchema> = {}

/** Validate and return a single offering (product) entry. */
export function defineOffering(entry: z.input<typeof ProductSchema>): z.infer<typeof ProductSchema> {
  return ProductSchema.parse(entry)
}

/** Validate and return an id-keyed map of offering entries. */
export function defineOfferings(
  entries: readonly z.input<typeof ProductSchema>[]
): Record<string, z.infer<typeof ProductSchema>> {
  return defineDomainRecord(ProductSchema, entries)
}

export type Product = z.infer<typeof ProductSchema>
export type OfferingsDomain = z.infer<typeof OfferingsDomainSchema>
export type PricingModel = z.infer<typeof PricingModelSchema>
