// src/core/eval/strategy/middleware.ts
// Middleware contracts for the three-layer security model.
//
// Layer 1: Kernel governance (enforcement.ts) — non-removable, coarse-grained
// Layer 2: SecurityMiddleware — configurable, fine-grained, can only DENY
// Layer 3: ObservationMiddleware — configurable, read-only, cannot influence execution
//
// This is a KERNEL file — it defines the interfaces that packages implement.

import type { State, StepOutcome } from "../machine";
import type { Val } from "../values";
import type { OpCall } from "../../effects/opcall";
import type { RunResult } from "./contract";

// ─────────────────────────────────────────────────────────────────
// SecurityMiddleware: Layer 2 — fine-grained policy (can deny)
// ─────────────────────────────────────────────────────────────────

/**
 * SecurityMiddleware can inspect and DENY operations.
 * It sits between kernel governance and strategy dispatch.
 *
 * Key properties:
 * - checkOp returns boolean: true = allow, false = deny
 * - Cannot modify state (no state mutation)
 * - Cannot add capabilities (can only narrow)
 * - Runs BEFORE observation middleware
 *
 * Examples: rate limiting, model filtering, path restriction,
 *           argument validation, anomaly detection, circuit breaker
 */
export interface SecurityMiddleware {
  /** Unique middleware name (matches package name) */
  readonly name: string;

  /** Human-readable description */
  readonly description: string;

  /**
   * Check whether an operation should be allowed.
   * @returns true to allow, false to deny
   */
  checkOp(
    state: State,
    opcall: OpCall,
    config: Record<string, unknown>,
  ): boolean | Promise<boolean>;

  /**
   * Optional: initialize with configuration.
   * Called once when the middleware is first activated.
   */
  init?(config: Record<string, unknown>): void | Promise<void>;

  /**
   * Optional: clean up resources.
   */
  dispose?(): void | Promise<void>;
}

// ─────────────────────────────────────────────────────────────────
// ObservationMiddleware: Layer 3 — read-only monitoring
// ─────────────────────────────────────────────────────────────────

/**
 * ObservationMiddleware can observe but NOT influence execution.
 * All methods return void — they cannot deny, modify, or redirect.
 *
 * Key properties:
 * - All methods return void (no influence on execution)
 * - Runs AFTER security middleware
 * - Cannot see denied operations (security middleware blocks first)
 *
 * Examples: trace logging, audit logging, profiling,
 *           replay recording, metrics emission
 */
export interface ObservationMiddleware {
  /** Unique middleware name (matches package name) */
  readonly name: string;

  /** Human-readable description */
  readonly description: string;

  /**
   * Called when an operation is about to be dispatched.
   * The operation has already passed security checks.
   */
  onOp?(state: State, opcall: OpCall): void;

  /**
   * Called after each step (StepOutcome from stepOnce).
   */
  onStep?(outcome: StepOutcome): void;

  /**
   * Called when evaluation completes with a result.
   */
  onResult?(result: RunResult): void;

  /**
   * Called when evaluation fails with an error.
   */
  onError?(error: Error): void;

  /**
   * Called after an operation completes (with the result state).
   */
  afterOp?(state: State, opcall: OpCall, result: State): void;

  /**
   * Optional: initialize with configuration.
   */
  init?(config: Record<string, unknown>): void | Promise<void>;

  /**
   * Optional: clean up resources.
   */
  dispose?(): void | Promise<void>;
}

// ─────────────────────────────────────────────────────────────────
// MiddlewareConfig: configuration for middleware activation
// ─────────────────────────────────────────────────────────────────

export interface SecurityMiddlewareConfig {
  /** Middleware name (must match a registered SecurityMiddleware) */
  name: string;
  /** Middleware-specific configuration */
  config: Record<string, unknown>;
}

export interface ObservationMiddlewareConfig {
  /** Middleware name (must match a registered ObservationMiddleware) */
  name: string;
  /** Middleware-specific configuration */
  config: Record<string, unknown>;
}
