/**
 * CapabilityRegistry - Lifecycle management for capabilities
 *
 * Implements contracts §18; DD §9.5.
 * Lifecycle: discovered → validated → doctor_checked → enabled → registered → active.
 * Trust levels affect default posture, never bypass ToolRegistry/PermissionEngine.
 *
 * @module packages/runtime/src/capabilities/CapabilityRegistry
 */

import type { ToolDefinition } from '@aircoding/contracts'

import { CapabilityManifestValidator, type CapabilityManifest, type ValidationResult } from './CapabilityManifestValidator.js'

export type CapabilityState = 'discovered' | 'validated' | 'doctor_checked' | 'enabled' | 'registered' | 'active' | 'disabled' | 'failed'

export interface CapabilityEntry {
  manifest: CapabilityManifest
  state: CapabilityState
  tool_definitions: ToolDefinition[]
  enabled_at?: string
  error?: string
}

/**
 * CapabilityRegistry manages the lifecycle of capabilities.
 * INV-4: Dependency installs go only through Doctor (no direct install).
 */
export class CapabilityRegistry {
  private capabilities: Map<string, CapabilityEntry> = new Map()
  private validator: CapabilityManifestValidator
  private tool_registry: ToolRegistry | null = null

  constructor() {
    this.validator = createCapabilityManifestValidator()
  }

  /**
   * Set the tool registry for registering tools.
   */
  set_tool_registry(registry: ToolRegistry): void {
    this.tool_registry = registry
  }

  /**
   * Discover a capability manifest.
   */
  discover(manifest: CapabilityManifest): { ok: boolean; capability_id?: string; error?: string } {
    const capability_id = `${manifest.name}@${manifest.version}`

    if (this.capabilities.has(capability_id)) {
      return { ok: false, capability_id, error: 'Capability already discovered' }
    }

    const entry: CapabilityEntry = {
      manifest,
      state: 'discovered',
      tool_definitions: []
    }

    this.capabilities.set(capability_id, entry)
    return { ok: true, capability_id }
  }

  /**
   * Validate a discovered capability.
   */
  validate(capability_id: string): ValidationResult {
    const entry = this.capabilities.get(capability_id)
    if (!entry) {
      return { valid: false, errors: [{ field: 'capability_id', message: 'Capability not found', code: 'NOT_FOUND' }], warnings: [] }
    }

    const result = this.validator.validate(entry.manifest)

    if (result.valid) {
      entry.state = 'validated'
      // Convert capability tools to ToolDefinitions
      entry.tool_definitions = this.convert_to_tool_definitions(entry.manifest)
    } else {
      entry.state = 'failed'
      entry.error = result.errors.map(e => e.message).join('; ')
    }

    return result
  }

  /**
   * Doctor check - verify the capability is safe to enable.
   * This is a placeholder - actual implementation would integrate with DoctorService.
   */
  async doctor_check(capability_id: string): Promise<{ ok: boolean; error?: string }> {
    const entry = this.capabilities.get(capability_id)
    if (!entry) {
      return { ok: false, error: 'Capability not found' }
    }

    if (entry.state !== 'validated') {
      return { ok: false, error: `Capability must be validated first, current state: ${entry.state}` }
    }

    // Stub: would run doctor checks
    entry.state = 'doctor_checked'
    return { ok: true }
  }

  /**
   * Enable a capability after all checks pass.
   */
  enable(capability_id: string): { ok: boolean; error?: string } {
    const entry = this.capabilities.get(capability_id)
    if (!entry) {
      return { ok: false, error: 'Capability not found' }
    }

    // Must pass doctor_check before enabling
    if (entry.state !== 'doctor_checked') {
      return { ok: false, error: `Capability must pass doctor_check first, current state: ${entry.state}` }
    }

    entry.state = 'enabled'
    entry.enabled_at = new Date().toISOString()
    return { ok: true }
  }

  /**
   * Register tools from an enabled capability into ToolRegistry.
   */
  register_tools(capability_id: string): { ok: boolean; registered_count: number; error?: string } {
    const entry = this.capabilities.get(capability_id)
    if (!entry) {
      return { ok: false, registered_count: 0, error: 'Capability not found' }
    }

    if (entry.state !== 'enabled') {
      return { ok: false, registered_count: 0, error: `Capability must be enabled first, current state: ${entry.state}` }
    }

    if (!this.tool_registry) {
      return { ok: false, registered_count: 0, error: 'Tool registry not set' }
    }

    // Register all tools
    let registered_count = 0
    for (const tool_def of entry.tool_definitions) {
      // Create a stub executor for each tool
      const executor = create_stub_executor(tool_def.name)
      this.tool_registry.register(tool_def.name, tool_def, executor)
      registered_count++
    }

    entry.state = 'active'
    return { ok: true, registered_count }
  }

  /**
   * Disable a capability and remove its tools.
   */
  disable(capability_id: string): { ok: boolean; error?: string } {
    const entry = this.capabilities.get(capability_id)
    if (!entry) {
      return { ok: false, error: 'Capability not found' }
    }

    // Remove tools from registry if active
    if (entry.state === 'active' && this.tool_registry) {
      for (const tool_def of entry.tool_definitions) {
        this.tool_registry.unregister(tool_def.name)
      }
    }

    entry.state = 'disabled'
    return { ok: true }
  }

  /**
   * List all capabilities.
   */
  list(): Array<{ id: string; name: string; version: string; state: CapabilityState }> {
    return Array.from(this.capabilities.entries()).map(([id, entry]) => ({
      id,
      name: entry.manifest.name,
      version: entry.manifest.version,
      state: entry.state
    }))
  }

  /**
   * Get a capability by ID.
   */
  get(capability_id: string): CapabilityEntry | undefined {
    return this.capabilities.get(capability_id)
  }

  /**
   * Convert capability tools to ToolDefinition format.
   */
  private convert_to_tool_definitions(manifest: CapabilityManifest): ToolDefinition[] {
    return manifest.tools.map(tool => ({
      name: tool.name,
      category: tool.category || 'custom',
      description: `${manifest.name} tool: ${tool.name}`,
      input_schema: tool.input_schema || { type: 'object', properties: {} },
      permissions: {
        read: tool.permissions?.read ?? false,
        write: tool.permissions?.write ?? false,
        network: tool.permissions?.network ?? false
      },
      streaming: false
    }))
  }
}

function create_stub_executor(tool_name: string): (call: any) => Promise<any> {
  return async (call: any) => ({
    call_id: call.id,
    tool_name,
    type: 'text' as const,
    content: { message: `Tool ${tool_name} executed (capability stub)` },
    metadata: { timestamp: new Date().toISOString() }
  })
}

export function createCapabilityRegistry(): CapabilityRegistry {
  return new CapabilityRegistry()
}

// Placeholder for ToolRegistry type (would be imported in real implementation)
interface ToolRegistry {
  register(name: string, definition: ToolDefinition, executor: (call: any) => Promise<any>): void
  unregister(name: string): void
}