// Copyright (c) 2026 Hellmai Ltd
// SPDX-License-Identifier: AGPL-3.0-only

/**
 * Pack-local LumenFlow configuration schema (WU-2694).
 *
 * Mirrors the shape of `@lumenflow/core/lumenflow-config-schema` using
 * hand-maintained TypeScript interfaces plus default-value constants. The pack
 * side deliberately avoids a full Zod composition to keep the invariant
 * "pack src/ MUST stay core-free": the authoritative Zod composition in core
 * transitively depends on `delivery-review-contract`, per-section schemas, and
 * other core-only modules that have not yet been migrated (INIT-058 Layer 4).
 *
 * Consumers that need a typed view of `workspace.yaml`'s `software_delivery`
 * block can import from this file without crossing the package boundary.
 * Drift against core's composition is enforced by
 * `integration-tests/tests/config-parity.test.ts` — any field added to core's
 * `LumenFlowConfig` must either be added here or explicitly waived in the
 * drift-guard.
 *
 * @module config/schemas/lumenflow-config-schema
 */

import { DURATION_MS } from '@lumenflow/kernel/primitives/duration-utils';

import { LUMENFLOW_CLIENT_IDS } from '../../constants/client-ids.js';
import { DOCS_LAYOUT_PRESETS } from '../../constants/docs-layout-presets.js';
import {
  DEFAULT_MAX_ESLINT_WARNINGS,
  DEFAULT_MIN_COVERAGE,
} from '../../constants/gate-constants.js';

const DEFAULT_LAYOUT = DOCS_LAYOUT_PRESETS.simple;

// ---------------------------------------------------------------------------
// Directories
// ---------------------------------------------------------------------------

export interface DirectoriesConfig {
  appsWeb: string;
  worktrees: string;
  ai: string;
  claude: string;
  docs: string;
  packages: string;
  tools: string;
  memoryBank: string;
  wuDir: string;
  initiativesDir: string;
  backlogPath: string;
  statusPath: string;
  skillsDir: string;
  agentsDir: string;
  adrDir: string;
  plansDir: string;
  templatesDir: string;
  onboardingDir: string;
  completeGuidePath: string;
  quickRefPath: string;
  startingPromptPath: string;
  sizingGuidePath: string;
  governancePath: string;
  safeGitPath: string;
}

export const DIRECTORIES_DEFAULTS: DirectoriesConfig = {
  appsWeb: '',
  worktrees: 'worktrees/',
  ai: 'ai/',
  claude: '.claude/',
  docs: 'docs/',
  packages: 'packages/',
  tools: 'tools/',
  memoryBank: 'memory-bank/',
  wuDir: `${DEFAULT_LAYOUT.tasks}/wu`,
  initiativesDir: `${DEFAULT_LAYOUT.tasks}/initiatives`,
  backlogPath: `${DEFAULT_LAYOUT.tasks}/backlog.md`,
  statusPath: `${DEFAULT_LAYOUT.tasks}/status.md`,
  skillsDir: '.claude/skills',
  agentsDir: '.claude/agents',
  adrDir: DEFAULT_LAYOUT.adrDir,
  plansDir: `${DEFAULT_LAYOUT.operations}/plans`,
  templatesDir: '.lumenflow/templates',
  onboardingDir: DEFAULT_LAYOUT.onboarding,
  completeGuidePath: DEFAULT_LAYOUT.completeGuidePath,
  quickRefPath: DEFAULT_LAYOUT.quickRefPath,
  startingPromptPath: DEFAULT_LAYOUT.startingPromptPath,
  sizingGuidePath: DEFAULT_LAYOUT.sizingGuidePath,
  governancePath: DEFAULT_LAYOUT.governancePath,
  safeGitPath: 'scripts/safe-git',
};

// ---------------------------------------------------------------------------
// State paths
// ---------------------------------------------------------------------------

export interface EventArchivalConfig {
  archiveAfter: number;
  keepArchives: boolean;
}

export interface StatePathsConfig {
  base: string;
  stateDir: string;
  archiveDir: string;
  stampsDir: string;
  mergeLock: string;
  telemetry: string;
  flowLog: string;
  sessions: string;
  incidents: string;
  commandsLog: string;
  eventArchival: EventArchivalConfig;
}

export const STATE_PATHS_DEFAULTS: StatePathsConfig = {
  base: '.lumenflow',
  stateDir: '.lumenflow/state',
  archiveDir: '.lumenflow/archive',
  stampsDir: '.lumenflow/stamps',
  mergeLock: '.lumenflow/merge.lock',
  telemetry: '.lumenflow/telemetry',
  flowLog: '.lumenflow/flow.log',
  sessions: '.lumenflow/sessions',
  incidents: '.lumenflow/incidents',
  commandsLog: '.lumenflow/commands.log',
  eventArchival: {
    archiveAfter: DURATION_MS.NINETY_DAYS,
    keepArchives: true,
  },
};

// ---------------------------------------------------------------------------
// Git
// ---------------------------------------------------------------------------

export interface PushRetryConfig {
  enabled: boolean;
  retries: number;
  min_delay_ms: number;
  max_delay_ms: number;
  jitter: boolean;
}

export interface GitConfig {
  mainBranch: string;
  defaultRemote: string;
  laneBranchPrefix: string;
  tempBranchPrefix: string;
  realGitPath: string;
  maxBranchDrift: number;
  branchDriftWarning: number;
  branchDriftInfo: number;
  requireRemote: boolean;
  agentBranchPatterns: string[];
  agentBranchPatternsOverride?: string[];
  disableAgentPatternRegistry: boolean;
  push_retry: PushRetryConfig;
}

export const GIT_DEFAULTS: GitConfig = {
  mainBranch: 'main',
  defaultRemote: 'origin',
  laneBranchPrefix: 'lane/',
  tempBranchPrefix: 'tmp/',
  realGitPath: '/usr/bin/git',
  maxBranchDrift: 20,
  branchDriftWarning: 15,
  branchDriftInfo: 10,
  requireRemote: true,
  agentBranchPatterns: [],
  disableAgentPatternRegistry: false,
  push_retry: {
    enabled: true,
    retries: 3,
    min_delay_ms: 100,
    max_delay_ms: 1000,
    jitter: true,
  },
};

// ---------------------------------------------------------------------------
// WU + IDs
// ---------------------------------------------------------------------------

export type WuBriefPolicyMode = 'off' | 'manual' | 'auto' | 'required';

export interface WuBriefConfig {
  policyMode: WuBriefPolicyMode;
  freshnessMinutes: number;
}

export interface WuConfig {
  idPattern: string;
  minDescriptionLength: number;
  maxCommitSubject: number;
  defaultPriority: string;
  defaultStatus: string;
  defaultType: string;
  brief: WuBriefConfig;
}

export const WU_DEFAULTS: WuConfig = {
  idPattern: '^WU-\\d+$',
  minDescriptionLength: 50,
  maxCommitSubject: 100,
  defaultPriority: 'P2',
  defaultStatus: 'ready',
  defaultType: 'feature',
  brief: {
    policyMode: 'auto',
    freshnessMinutes: 1440,
  },
};

export interface IdFormatConfig {
  width: number;
  strict: boolean;
  prefix: string;
}

export const WU_ID_DEFAULTS: IdFormatConfig = {
  width: 4,
  strict: true,
  prefix: 'WU-',
};

export const INITIATIVE_ID_DEFAULTS: IdFormatConfig = {
  width: 3,
  strict: true,
  prefix: 'INIT-',
};

// ---------------------------------------------------------------------------
// Gates (narrow subset — downstream cohorts only read a few fields)
// ---------------------------------------------------------------------------

export interface GatesConfig {
  maxEslintWarnings: number;
  enableCoverage: boolean;
  minCoverage: number;
  [extra: string]: unknown;
}

export const GATES_DEFAULTS: GatesConfig = {
  maxEslintWarnings: DEFAULT_MAX_ESLINT_WARNINGS,
  enableCoverage: true,
  minCoverage: DEFAULT_MIN_COVERAGE,
};

// ---------------------------------------------------------------------------
// UI + YAML + operational toggles
// ---------------------------------------------------------------------------

export interface UiConfig {
  errorBoxWidth: number;
  statusPreviewLines: number;
  readinessBoxWidth: number;
}

export const UI_DEFAULTS: UiConfig = {
  errorBoxWidth: 70,
  statusPreviewLines: 5,
  readinessBoxWidth: 50,
};

export interface YamlConfig {
  lineWidth: number;
}

export const YAML_DEFAULTS: YamlConfig = {
  lineWidth: 100,
};

export type ValidationMode = 'off' | 'warn' | 'error';

export interface ExperimentalConfig {
  context_validation: boolean;
  validation_mode: ValidationMode;
  show_next_steps: boolean;
  recovery_command: boolean;
}

export const EXPERIMENTAL_DEFAULTS: ExperimentalConfig = {
  context_validation: true,
  validation_mode: 'warn',
  show_next_steps: true,
  recovery_command: true,
};

export type CleanupTrigger = 'on_done' | 'on_init' | 'manual';

export interface CleanupConfig {
  trigger: CleanupTrigger;
  commit_message: string;
}

export const CLEANUP_DEFAULTS: CleanupConfig = {
  trigger: 'on_done',
  commit_message: 'chore: lumenflow state cleanup [skip ci]',
};

export interface MethodologyTelemetryConfig {
  enabled: boolean;
}

export interface TelemetryConfig {
  methodology: MethodologyTelemetryConfig;
}

export const TELEMETRY_DEFAULTS: TelemetryConfig = {
  methodology: { enabled: false },
};

export interface EscalationConfig {
  email: string;
}

export const ESCALATION_DEFAULTS: EscalationConfig = {
  email: 'escalation@example.com',
};

// ---------------------------------------------------------------------------
// Memory (narrow — only top-level fields with defaults)
// ---------------------------------------------------------------------------

export interface MemoryConfig {
  directory: string;
  sessionTtl: number;
  checkpointTtl: number;
  enableAutoCleanup: boolean;
  delegation_context_max_size: number;
  [extra: string]: unknown;
}

export const MEMORY_DEFAULTS: MemoryConfig = {
  directory: 'memory-bank/',
  sessionTtl: DURATION_MS.SEVEN_DAYS,
  checkpointTtl: DURATION_MS.THIRTY_DAYS,
  enableAutoCleanup: true,
  delegation_context_max_size: 4096,
};

// ---------------------------------------------------------------------------
// Agents (narrow — only defaultClient, which many cohorts need)
// ---------------------------------------------------------------------------

export interface AgentsConfig {
  defaultClient: string;
  [extra: string]: unknown;
}

export const AGENTS_DEFAULTS: AgentsConfig = {
  defaultClient: LUMENFLOW_CLIENT_IDS.CLAUDE_CODE,
};

// ---------------------------------------------------------------------------
// Cloud + lanes + methodology: loose pass-through
// ---------------------------------------------------------------------------

export interface CloudEnvSignal {
  name: string;
  equals?: string;
}

export interface CloudConfig {
  auto_detect: boolean;
  env_signals: CloudEnvSignal[];
  [extra: string]: unknown;
}

export const CLOUD_DEFAULTS: CloudConfig = {
  auto_detect: false,
  env_signals: [],
};

// ---------------------------------------------------------------------------
// Top-level LumenflowConfig
// ---------------------------------------------------------------------------

export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
export type TestRunner = 'vitest' | 'jest' | 'mocha';

export interface LumenflowConfig {
  version: string;
  directories: DirectoriesConfig;
  state: StatePathsConfig;
  git: GitConfig;
  wu: WuConfig;
  wuId: IdFormatConfig;
  initiativeId: IdFormatConfig;
  gates: GatesConfig;
  memory: MemoryConfig;
  ui: UiConfig;
  yaml: YamlConfig;
  agents: AgentsConfig;
  experimental: ExperimentalConfig;
  cleanup: CleanupConfig;
  telemetry: TelemetryConfig;
  methodology?: Record<string, unknown>;
  cloud: CloudConfig;
  lanes?: Record<string, unknown>;
  escalation: EscalationConfig;
  package_manager: PackageManager;
  test_runner: TestRunner;
  build_command: string;
}

/**
 * Top-level defaults for `LumenflowConfig`. Matches the `.parse({})` output of
 * `core`'s `LumenFlowConfigSchema` for every field exposed here. The drift-guard
 * in `integration-tests/tests/config-parity.test.ts` walks these keys and
 * asserts field-for-field parity with core's output.
 */
export const LUMENFLOW_CONFIG_DEFAULTS: LumenflowConfig = {
  version: '1.0.0',
  directories: DIRECTORIES_DEFAULTS,
  state: STATE_PATHS_DEFAULTS,
  git: GIT_DEFAULTS,
  wu: WU_DEFAULTS,
  wuId: WU_ID_DEFAULTS,
  initiativeId: INITIATIVE_ID_DEFAULTS,
  gates: GATES_DEFAULTS,
  memory: MEMORY_DEFAULTS,
  ui: UI_DEFAULTS,
  yaml: YAML_DEFAULTS,
  agents: AGENTS_DEFAULTS,
  experimental: EXPERIMENTAL_DEFAULTS,
  cleanup: CLEANUP_DEFAULTS,
  telemetry: TELEMETRY_DEFAULTS,
  cloud: CLOUD_DEFAULTS,
  escalation: ESCALATION_DEFAULTS,
  package_manager: 'pnpm',
  test_runner: 'vitest',
  build_command: 'pnpm build',
};
