/**
 * record_directive — the PM's standing instructions ("pilots come first"),
 * appended to an append-only JSONL ledger in the pm-state repo (decisions.md D4,
 * pm-state.md). A directive is *intent*: it's logged verbatim; its effects land
 * later through apply_changes. Merge is concatenation — order derives from `ts`
 * at read time, so two writers never conflict. `seq` is a display ordinal
 * computed on read, never stored. This module is pure serialize/parse; the
 * append (read → concat → write) is the bridge's job.
 */

export type DirectiveKind = 'reprioritize' | 'reestimate' | 'set-deadline' | 'scope' | 'capacity' | 'note'

export type DirectiveStatus = 'proposed' | 'accepted' | 'amended' | 'withdrawn'

export interface DirectiveTarget {
  issue?: number
  milestone?: number
  member?: string
}

/** What the record_directive tool captures. */
export interface DirectiveInput {
  kind: DirectiveKind
  /** Verbatim PM words, shown in the ledger. */
  quote: string
  target?: DirectiveTarget
  /** Structured effect the scheduler applies, e.g. { priority: 1 }. */
  params?: Record<string, unknown>
  rationale?: string
}

/** A ledger entry — an input plus its durable id/ts/status. */
export interface DirectiveEntry extends DirectiveInput {
  id: string
  ts: string
  status: DirectiveStatus
}

/** A ledger entry as read back, with a computed display ordinal. */
export interface DirectiveRecord extends DirectiveEntry {
  seq: number
}

const DIRECTIVE_KINDS: readonly DirectiveKind[] = [
  'reprioritize',
  'reestimate',
  'set-deadline',
  'scope',
  'capacity',
  'note',
]

/** Normalize a raw tool payload into a DirectiveInput (unknown kind → note). */
export function toDirectiveInput(raw: unknown): DirectiveInput {
  const r = (raw ?? {}) as Record<string, unknown>
  const kind = DIRECTIVE_KINDS.includes(r.kind as DirectiveKind) ? (r.kind as DirectiveKind) : 'note'
  const target = (r.target ?? undefined) as DirectiveTarget | undefined
  return {
    kind,
    quote: typeof r.quote === 'string' ? r.quote : '',
    target: target && (target.issue || target.milestone || target.member) ? target : undefined,
    params: (r.params && typeof r.params === 'object' ? (r.params as Record<string, unknown>) : undefined),
    rationale: typeof r.rationale === 'string' ? r.rationale : undefined,
  }
}

/** Build a full entry from an input + externally-supplied id/ts (Date/uuid live in the caller). */
export function makeDirectiveEntry(
  input: DirectiveInput,
  id: string,
  ts: string,
  status: DirectiveStatus = 'accepted',
): DirectiveEntry {
  return { ...input, id, ts, status }
}

/** One JSONL line (no trailing newline — the caller joins). */
export function serializeDirective(entry: DirectiveEntry): string {
  return JSON.stringify(entry)
}

/**
 * Parse a JSONL log into records ordered by `ts` (then id for stability), with a
 * 1-based `seq` assigned on read. Blank/corrupt lines are skipped, not fatal.
 */
export function parseDirectiveLog(text: string): DirectiveRecord[] {
  const entries: DirectiveEntry[] = []
  for (const line of text.split('\n')) {
    const trimmed = line.trim()
    if (!trimmed) continue
    try {
      const e = JSON.parse(trimmed) as DirectiveEntry
      if (e && typeof e.id === 'string' && typeof e.ts === 'string') entries.push(e)
    } catch {
      // skip a corrupt line rather than lose the whole ledger
    }
  }
  entries.sort((a, b) => (a.ts === b.ts ? a.id.localeCompare(b.id) : a.ts.localeCompare(b.ts)))
  return entries.map((e, i) => ({ ...e, seq: i + 1 }))
}

/** Append a serialized entry to existing log text (concatenation merge). */
export function appendDirective(existing: string, entry: DirectiveEntry): string {
  const base = existing.endsWith('\n') || existing === '' ? existing : existing + '\n'
  return `${base}${serializeDirective(entry)}\n`
}
