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

// ---------------------------------------------------------------------------
// Measurable outcome schema — one trackable result that supports a goal.
// The field name `keyResults` is used for compatibility with OKR tooling;
// user-facing surfaces and documentation MUST say "measurable outcomes",
// never "key results" or "OKR".
// ---------------------------------------------------------------------------

export const KeyResultSchema = z.object({
  /** Stable unique identifier for the measurable outcome (e.g. "kr-revenue-q1"). */
  id: z.string().trim().min(1).max(100),
  /** Plain-language description of this measurable outcome (e.g. "Increase trial-to-paid conversion"). */
  description: z.string().trim().min(1).max(500),
  /**
   * What is being measured — the metric name (e.g. "monthly revenue", "NPS score",
   * "trial-to-paid conversion rate"). Free-form string.
   */
  targetMetric: z.string().trim().min(1).max(200),
  /** Current measured value. Defaults to 0 when not yet tracked. */
  currentValue: z.number().default(0),
  /**
   * Target value to reach for this measurable outcome to be considered achieved.
   * Optional — omit if the outcome is directional (e.g. "reduce churn") without
   * a hard numeric target.
   */
  targetValue: z.number().optional()
})

// ---------------------------------------------------------------------------
// Objective schema — one goal the organization is working toward.
// User-facing label is "goal"; this schema type is named Objective for
// structural continuity with OKR tooling. Do NOT expose "OKR", "objective",
// or "key result" in any user-facing label or documentation.
//
// Period fields use ISO 8601 date strings (YYYY-MM-DD). Cross-schema
// validation (periodEnd > periodStart) is enforced in
// `OrganizationModelSchema.superRefine()`.
// ---------------------------------------------------------------------------

const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/

export const ObjectiveSchema = z.object({
  /** Stable unique identifier for the goal (e.g. "goal-grow-arr-q1-2026"). */
  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(),
  /** Plain-language description of what the organization wants to achieve. */
  description: z.string().trim().min(1).max(1000),
  /**
   * Start of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
   * Must be strictly before `periodEnd`.
   */
  periodStart: z.string().regex(ISO_DATE_REGEX, 'periodStart must be an ISO date string (YYYY-MM-DD)'),
  /**
   * End of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
   * Must be strictly after `periodStart`.
   * Enforced via `OrganizationModelSchema.superRefine()`.
   */
  periodEnd: z.string().regex(ISO_DATE_REGEX, 'periodEnd must be an ISO date string (YYYY-MM-DD)'),
  /**
   * List of measurable outcomes that define success for this goal.
   * Defaults to empty array so goals can be declared before outcomes are defined.
   */
  keyResults: z.array(KeyResultSchema).default([])
})

// ---------------------------------------------------------------------------
// Goals domain schema — a collection of goals the organization is pursuing.
// ---------------------------------------------------------------------------

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

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

export const DEFAULT_ORGANIZATION_MODEL_GOALS: z.infer<typeof GoalsDomainSchema> = {}

/** Validate and return a single goal (objective) entry. */
export function defineGoal(entry: z.input<typeof ObjectiveSchema>): z.infer<typeof ObjectiveSchema> {
  return ObjectiveSchema.parse(entry)
}

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

export type KeyResult = z.infer<typeof KeyResultSchema>
export type Objective = z.infer<typeof ObjectiveSchema>
export type GoalsDomain = z.infer<typeof GoalsDomainSchema>
