// src/core/security/SecurityConfiguration.ts
//
// Vision 27 §11.11: Environment-based security configuration
//
// Mark Miller (Capability Security, E Language):
//   "Security code must always run. blocklist:[] exercises the code path."
//
// Joe Armstrong (Erlang, "Programming Erlang"):
//   "Policy changes, mechanism stays. Same checks, different config."
//
// Butler Lampson (Turing Award, Capability Systems):
//   "Hierarchical config correct - env overrides defaults."

import type { ILispSecurityContext } from './LispSecurityContext';
import { DEVELOPER_CONTEXT, COMPONENT_CONTEXT, SANDBOX_CONTEXT } from './LispSecurityContext';

/**
 * Security runtime mode.
 *
 * Determines which default security context is used.
 */
export type SecurityMode = 'production' | 'development' | 'test';

/**
 * Security configuration for the runtime.
 */
export interface ISecurityConfiguration {
  /** Runtime mode */
  mode: SecurityMode;

  /** Default context for new components */
  defaultContext: ILispSecurityContext;

  /** Whether env vars can override */
  allowEnvOverride: boolean;
}

/**
 * Detect security mode from environment.
 *
 * Priority:
 * 1. MATRIX_SECURITY_MODE env var (explicit)
 * 2. NODE_ENV (implicit)
 * 3. Default to 'production' (safe)
 *
 * Butler Lampson (Turing Award):
 *   "Default to most restrictive. Explicit override for less restrictive."
 */
function detectSecurityMode(): SecurityMode {
  // Check explicit override first
  const explicitMode = typeof process !== 'undefined'
    ? process.env?.MATRIX_SECURITY_MODE
    : undefined;

  if (explicitMode === 'development' || explicitMode === 'test') {
    return explicitMode;
  }

  // Check NODE_ENV
  const nodeEnv = typeof process !== 'undefined'
    ? process.env?.NODE_ENV
    : undefined;

  if (nodeEnv === 'development' || nodeEnv === 'test') {
    return nodeEnv as SecurityMode;
  }

  // Browser environment - check for localhost
  if (typeof window !== 'undefined') {
    const hostname = window.location?.hostname;
    if (hostname === 'localhost' || hostname === '127.0.0.1') {
      return 'development';
    }
  }

  // Safe default - production is most restrictive
  return 'production';
}

// Cached configuration
let cachedConfig: ISecurityConfiguration | null = null;

/**
 * Get the security configuration for current environment.
 *
 * Mark Miller (E Language):
 *   "Configuration is computed once, then cached. Mode detection
 *    at startup prevents mid-session changes."
 */
export function getSecurityConfiguration(): ISecurityConfiguration {
  if (cachedConfig) {
    return cachedConfig;
  }

  const mode = detectSecurityMode();

  // Select default context based on mode
  // Production: COMPONENT_CONTEXT (restricted but functional)
  // Development/Test: DEVELOPER_CONTEXT (permissive for debugging)
  const defaultContext = mode === 'production'
    ? COMPONENT_CONTEXT
    : DEVELOPER_CONTEXT;

  cachedConfig = {
    mode,
    defaultContext,
    allowEnvOverride: mode !== 'production',
  };

  // Log security mode at startup (once)
  if (mode === 'production') {
    // eslint-disable-next-line no-console -- startup security mode announcement in kernel bootstrap
    console.log('[Security] Production mode: COMPONENT_CONTEXT active');
  } else {
    // eslint-disable-next-line no-console -- startup security mode announcement in kernel bootstrap
    console.log(`[Security] ${mode} mode: DEVELOPER_CONTEXT active (security checks still run)`);
  }

  return cachedConfig;
}

/**
 * Get the default security context for components.
 *
 * This is the context used when no explicit context is provided.
 *
 * Robert C. Martin (SOLID, "Clean Code"):
 *   "Single point of access for default context. Easy to audit."
 */
export function getDefaultSecurityContext(): ILispSecurityContext {
  return getSecurityConfiguration().defaultContext;
}

/**
 * Check if we're in development mode.
 */
export function isDevMode(): boolean {
  return getSecurityConfiguration().mode === 'development';
}

/**
 * Check if we're in production mode.
 */
export function isProductionMode(): boolean {
  return getSecurityConfiguration().mode === 'production';
}

/**
 * Check if we're in test mode.
 */
export function isTestMode(): boolean {
  return getSecurityConfiguration().mode === 'test';
}

/**
 * Reset cached configuration (for testing only).
 *
 * Kent Beck (TDD):
 *   "Tests need to reset state. Production code should never call this."
 */
export function _resetSecurityConfigurationForTesting(): void {
  cachedConfig = null;
}

/**
 * Get security context by name.
 *
 * Provides access to predefined contexts by name.
 */
export function getSecurityContextByName(
  name: 'sandbox' | 'component' | 'developer' | 'default'
): ILispSecurityContext {
  switch (name) {
    case 'sandbox':
      return SANDBOX_CONTEXT;
    case 'component':
      return COMPONENT_CONTEXT;
    case 'developer':
      return DEVELOPER_CONTEXT;
    case 'default':
      return getDefaultSecurityContext();
    default:
      // TypeScript exhaustiveness check
      const _exhaustive: never = name;
      return _exhaustive;
  }
}
