/**
 * CapabilityManifestValidator - Validates capability manifests
 *
 * Implements contracts §18; DD §9.5.
 * Validates schema_version=1, tool schemas, permissions.
 *
 * @module packages/runtime/src/capabilities/CapabilityManifestValidator
 */

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

export interface CapabilityManifest {
  schema_version: number
  name: string
  version: string
  description?: string
  tools: CapabilityTool[]
  dependencies?: string[]
  trust_level?: CapabilityTrustLevel
}

export interface CapabilityTool {
  name: string
  category?: string
  permissions?: {
    read?: boolean
    write?: boolean
    network?: boolean
  }
  input_schema?: Record<string, unknown>
}

export interface ValidationResult {
  valid: boolean
  errors: ValidationError[]
  warnings: ValidationWarning[]
}

export interface ValidationError {
  field: string
  message: string
  code: string
}

export interface ValidationWarning {
  field: string
  message: string
}

export class CapabilityManifestValidator {
  private static readonly SUPPORTED_SCHEMA_VERSION = 1
  private static readonly REQUIRED_FIELDS = ['schema_version', 'name', 'version', 'tools']
  private static readonly TRUST_LEVELS: readonly CapabilityTrustLevel[] = ['built_in', 'project_local', 'user_installed', 'verified_publisher', 'untrusted'] as const

  /**
   * Validate a capability manifest.
   */
  validate(manifest: unknown): ValidationResult {
    const errors: ValidationError[] = []
    const warnings: ValidationWarning[] = []

    if (!manifest || typeof manifest !== 'object') {
      errors.push({ field: 'manifest', message: 'Manifest must be an object', code: 'INVALID_TYPE' })
      return { valid: false, errors, warnings }
    }

    const obj = manifest as Record<string, unknown>

    // Check required fields
    for (const field of CapabilityManifestValidator.REQUIRED_FIELDS) {
      if (!(field in obj)) {
        errors.push({ field, message: `Required field missing: ${field}`, code: 'MISSING_FIELD' })
      }
    }

    // Validate schema_version
    if ('schema_version' in obj) {
      const schema_version = obj.schema_version
      if (typeof schema_version !== 'number') {
        errors.push({ field: 'schema_version', message: 'schema_version must be a number', code: 'INVALID_TYPE' })
      } else if (schema_version !== CapabilityManifestValidator.SUPPORTED_SCHEMA_VERSION) {
        errors.push({
          field: 'schema_version',
          message: `Unsupported schema_version: ${schema_version}. Supported: ${CapabilityManifestValidator.SUPPORTED_SCHEMA_VERSION}`,
          code: 'UNSUPPORTED_VERSION'
        })
      }
    }

    // Validate name
    if ('name' in obj && typeof obj.name !== 'string') {
      errors.push({ field: 'name', message: 'name must be a string', code: 'INVALID_TYPE' })
    } else if ('name' in obj && obj.name) {
      const name = obj.name as string
      if (!/^[a-z][a-z0-9_-]*$/.test(name)) {
        errors.push({ field: 'name', message: 'name must be lowercase alphanumeric with dashes/underscores', code: 'INVALID_FORMAT' })
      }
    }

    // Validate version
    if ('version' in obj && typeof obj.version !== 'string') {
      errors.push({ field: 'version', message: 'version must be a string', code: 'INVALID_TYPE' })
    } else if ('version' in obj && obj.version) {
      const version = obj.version as string
      if (!/^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$/.test(version)) {
        warnings.push({ field: 'version', message: 'version should follow semver format (e.g., 1.0.0)' })
      }
    }

    // Validate tools array
    if ('tools' in obj) {
      if (!Array.isArray(obj.tools)) {
        errors.push({ field: 'tools', message: 'tools must be an array', code: 'INVALID_TYPE' })
      } else {
        this.validate_tools(obj.tools as unknown[], errors, warnings)
      }
    }

    // Validate trust_level
    if ('trust_level' in obj) {
      const trust_level = obj.trust_level
      if (typeof trust_level !== 'string') {
        errors.push({ field: 'trust_level', message: 'trust_level must be a string', code: 'INVALID_TYPE' })
      } else if (!CapabilityManifestValidator.TRUST_LEVELS.includes(trust_level as typeof CapabilityManifestValidator.TRUST_LEVELS[number])) {
        errors.push({
          field: 'trust_level',
          message: `Invalid trust_level: ${trust_level}. Must be one of: ${CapabilityManifestValidator.TRUST_LEVELS.join(', ')}`,
          code: 'INVALID_VALUE'
        })
      }
    }

    return { valid: errors.length === 0, errors, warnings }
  }

  private validate_tools(tools: unknown[], errors: ValidationError[], warnings: ValidationWarning[]): void {
    tools.forEach((tool, index) => {
      if (!tool || typeof tool !== 'object') {
        errors.push({ field: `tools[${index}]`, message: 'Tool must be an object', code: 'INVALID_TYPE' })
        return
      }

      const t = tool as Record<string, unknown>

      // Validate tool name
      if (!('name' in t) || typeof t.name !== 'string') {
        errors.push({ field: `tools[${index}].name`, message: 'Tool name is required and must be a string', code: 'MISSING_FIELD' })
      }

      // Validate permissions object if present
      if ('permissions' in t && t.permissions) {
        if (typeof t.permissions !== 'object') {
          errors.push({ field: `tools[${index}].permissions`, message: 'permissions must be an object', code: 'INVALID_TYPE' })
        } else {
          const perms = t.permissions as Record<string, unknown>
          const valid_perms = ['read', 'write', 'network']
          for (const key of Object.keys(perms)) {
            if (!valid_perms.includes(key)) {
              warnings.push({ field: `tools[${index}].permissions.${key}`, message: `Unknown permission: ${key}` })
            }
            if (typeof perms[key] !== 'boolean') {
              errors.push({ field: `tools[${index}].permissions.${key}`, message: 'Permission value must be boolean', code: 'INVALID_TYPE' })
            }
          }
        }
      }
    })
  }
}

export function createCapabilityManifestValidator(): CapabilityManifestValidator {
  return new CapabilityManifestValidator()
}