# System Setup Module
# Orchestrates complete provisioning system setup and initialization
# Follows Nushell guidelines: explicit types, single purpose, no try-catch

# Selective imports (ADR-025 Phase 3 Layer 2).
# setup/detection.nu and setup/validation.nu star-imports were dead — dropped.
use lib_provisioning/setup/mod.nu [
    detect-architecture detect-os ensure-config-dirs get-config-base-path
    get-cpu-count get-current-user get-system-disk-gb get-system-hostname
    get-system-memory-gb get-timestamp-iso8601 print-setup-error
    print-setup-header print-setup-info print-setup-success print-setup-warning
    save-config-toml save-config-yaml
]
use lib_provisioning/setup/wizard.nu [
    run-minimal-setup run-setup-with-defaults run-setup-wizard
]
use lib_provisioning/utils/nickel_processor.nu [ncl-eval-soft]

# ============================================================================
# SYSTEM CONFIGURATION CREATION
# ============================================================================

# Create system configuration file
export def create-system-config-file [
    config_base: string
    config_data: record
] {
    let system_config_path = $"($config_base)/system.toml"

    let system_config = {
        version: "1.0.0"
        install_path: (config_data.install_path? | default "")
        os_name: (config_data.os_name? | default (detect-os))
        os_version: (config_data.os_version? | default "unknown")
        config_base_path: $config_base
        cache_base_path: $"($config_base)/cache"
        workspaces_dir: $"($config_base)/workspaces"
        system_architecture: (detect-architecture)
        cpu_count: (config_data.cpu_count? | default (get-cpu-count))
        memory_total_gb: (config_data.memory_gb? | default (get-system-memory-gb))
        disk_total_gb: (config_data.disk_gb? | default (get-system-disk-gb))
        setup_date: (get-timestamp-iso8601)
        setup_by_user: (get-current-user)
        setup_hostname: (get-system-hostname)
    }

    save-config-toml $system_config_path $system_config
}

# Create platform services configuration
export def create-platform-config-file [
    config_base: string
    config_data: record
] {
    let platform_config_path = $"($config_base)/platform/deployment.toml"

    let platform_config = {
        version: "1.0.0"
        deployment: {
            mode: (config_data.deployment_mode? | default "docker-compose")
            location_type: "local"
        }
        docker_compose: {
            enabled: true
            path: (config_data.docker_compose_path? | default ".")
        }
        kubernetes: {
            enabled: false
            namespace: "provisioning"
            kubeconfig: ""
            manifests_path: "./k8s"
        }
        remote_ssh: {
            enabled: false
            host: ""
            user: "deploy"
            ssh_key: "~/.ssh/id_rsa"
        }
        systemd: {
            enabled: false
            service_prefix: "provisioning-"
        }
        services: {
            orchestrator: {
                endpoint: "http://localhost:9090/health"
                timeout_seconds: 30
                type: "http"
            }
            control_center: {
                endpoint: "http://localhost:3000/health"
                timeout_seconds: 30
                type: "http"
            }
            kms_service: {
                endpoint: "http://localhost:3001/health"
                timeout_seconds: 30
                type: "http"
            }
        }
        platform: {
            orchestrator: {
                endpoint: "http://localhost:9090"
                api_version: "v1"
            }
            control_center: {
                url: "http://localhost:3000"
                token: ""
            }
            kms: {
                endpoint: "http://localhost:3001"
                backend: "rustyvault"
                rustyvault: {
                    enabled: true
                    master_key: ""
                }
            }
        }
    }

    save-config-toml $platform_config_path $platform_config
}

# Create user preferences configuration
export def create-user-preferences-file [
    config_base: string
    config_data: record
] {
    let user_prefs_path = $"($config_base)/user_preferences.toml"

    let user_prefs = {
        output_format: (config_data.output_format? | default "yaml")
        use_colors: (config_data.use_colors? | default true)
        file_viewer: (config_data.file_viewer? | default "bat")
        confirm_delete: (config_data.confirm_delete? | default true)
        confirm_deploy: (config_data.confirm_deploy? | default true)
        default_log_level: (config_data.default_log_level? | default "info")
        default_provider: (config_data.default_provider? | default "local")
        http_use_curl: (config_data.http_use_curl? | default false)
        http_timeout_seconds: (config_data.http_timeout_seconds? | default 30)
        terraform_auto_approve: (config_data.terraform_auto_approve? | default false)
        editor: (config_data.editor? | default "vim")
    }

    save-config-toml $user_prefs_path $user_prefs
}

# ============================================================================
# PROVIDER CONFIGURATION
# ============================================================================

# Create provider configuration file
export def create-provider-config-file [
    config_base: string
    provider_name: string
    credentials_source: string = ""
] {
    let provider_config_path = $"($config_base)/providers/($provider_name).toml"

    let provider_config = (match $provider_name {
        "upcloud" => {
            {
                api_url: "https://api.upcloud.com/1.3"
                interface: "API"
                credentials_source: ($credentials_source | default "rustyvault://system/providers/upcloud")
                timeout_seconds: 30
            }
        }
        "aws" => {
            {
                region: "us-east-1"
                credentials_source: ($credentials_source | default "rustyvault://system/providers/aws")
                timeout_seconds: 30
            }
        }
        "hetzner" => {
            {
                api_url: "https://api.hetzner.cloud/v1"
                credentials_source: ($credentials_source | default "rustyvault://system/providers/hetzner")
                timeout_seconds: 30
            }
        }
        "local" => {
            {
                base_path: "/tmp/provisioning-local"
                timeout_seconds: 10
            }
        }
        _ => {}
    })

    save-config-toml $provider_config_path $provider_config
}

# ============================================================================
# RUSTYVAULT BOOTSTRAP SETUP
# ============================================================================

# Create RustyVault bootstrap key placeholder
export def create-rustyvault-bootstrap-placeholder [
    config_base: string
] {
    let bootstrap_path = $"($config_base)/rustyvault_bootstrap.age"

    # Create placeholder file with instructions
    let bootstrap_content = "# RustyVault Bootstrap Key (SOPS-Encrypted)\n# This file contains the encrypted RustyVault master key\n# Generated: (get-timestamp-iso8601)\n#\n# To generate the actual key:\n#   age-keygen -o > ~/.age/keys.txt\n#   sops encrypt --age <public-key> rustyvault_bootstrap.age > .sops.yaml\n#\n# This is the ONLY secret stored with SOPS - all other credentials\n# are stored encrypted in RustyVault with encrypt/decrypt at-rest support.\n\n# Placeholder - run: provisioning setup rustyvault-bootstrap\n"

    let result = (do { $bootstrap_content | save -f $bootstrap_path } | complete)
    ($result.exit_code == 0)
}

# ============================================================================
# WORKSPACE REGISTRY
# ============================================================================

# Create workspace registry file
export def create-workspace-registry [
    config_base: string
] {
    let registry_path = $"($config_base)/workspaces_registry.yaml"

    let workspace_registry = {
        version: "1.0.0"
        active_workspace: ""
        workspaces: []
        created_at: (get-timestamp-iso8601)
        metadata: {
            initialized: true
        }
    }

    save-config-yaml $registry_path $workspace_registry
}

# ============================================================================
# CEDAR POLICIES SETUP
# ============================================================================

# Create default Cedar policies directory and files
export def setup-cedar-policies [
    config_base: string
] {
    let policies_dir = $"($config_base)/cedar-policies"

    # Create directory
    let mkdir_result = (do { mkdir $policies_dir } | complete)
    if ($mkdir_result.exit_code != 0) {
        return false
    }

    # Create default policies
    let default_policies = "// Default Cedar Authorization Policies\n// Version: 1.0.0\n// Auto-generated during system setup\n\n// Allow admin full access\npermit(\n  principal in Role::\"Admin\",\n  action,\n  resource\n);\n\n// Allow users workspace-scoped access\npermit(\n  principal in Workspace::\".*\",\n  action in [\n    Action::\"server.create\",\n    Action::\"server.read\",\n    Action::\"taskserv.install\"\n  ],\n  resource\n) when {\n  context has workspace_id &&\n  resource.workspace_id == principal.id\n};\n\n// Require MFA for production operations\nforbid(\n  principal,\n  action in [\n    Action::\"server.delete\",\n    Action::\"cluster.delete\",\n    Action::\"database.delete\"\n  ],\n  resource in Environment::\"production\"\n) unless {\n  context.mfa_verified == true\n};\n"

    let policies_file = $"($policies_dir)/default.cedar"
    let result = (do { $default_policies | save -f $policies_file } | complete)
    ($result.exit_code == 0)
}

# ============================================================================
# NICKEL CONFIGURATION GENERATION
# ============================================================================

# Get Nickel schema path for config type
def get-nickel-schema-path [config_type: string] {
    match $config_type {
        "system" => "provisioning/schemas/platform/system.ncl"
        "deployment" => "provisioning/schemas/platform/deployment.ncl"
        "user_preferences" => "provisioning/schemas/platform/user_preferences.ncl"
        "provider" => "provisioning/schemas/platform/provider.ncl"
        _ => ""
    }
}

# Generate Nickel system configuration from defaults
export def create-system-config-nickel [
    config_base: string
    profile: string = "developer"
] {
    let system_config_path = $"($config_base)/system.ncl"

    let os_name = (detect-os)
    let architecture = (detect-architecture)
    let cpu_count = (get-cpu-count)
    let memory_gb = (get-system-memory-gb)
    let disk_gb = (get-system-disk-gb)

    let system_nickel = $"# System Configuration (Nickel)
# Generated: (get-timestamp-iso8601)
# Profile: ($profile)

let helpers = import \"../../schemas/platform/common/helpers.ncl\" in
let system_schema = import \"../../schemas/platform/system.ncl\" in
let defaults = import \"../../schemas/platform/defaults/system-defaults.ncl\" in

# Compose: defaults + platform-specific values
helpers.compose_config defaults {} {
  version = \"1.0.0\",
  config_base_path = \"($config_base)\",
  os_name = '$os_name,
  system_architecture = '$architecture,
  cpu_count = $cpu_count,
  memory_total_gb = $memory_gb,
  disk_total_gb = $disk_gb,
  setup_date = \"(get-timestamp-iso8601)\",
  setup_by_user = \"(get-current-user)\",
  setup_hostname = \"(get-system-hostname)\",
}
| system_schema.SystemConfig
"

    let result = (do { $system_nickel | save -f $system_config_path } | complete)
    ($result.exit_code == 0)
}

# Generate Nickel platform deployment configuration from defaults + profile overlay
export def create-platform-config-nickel [
    config_base: string
    deployment_mode: string = "docker-compose"
    profile: string = "developer"
] {
    let platform_config_path = $"($config_base)/platform/deployment.ncl"

    let deployment_mode_tag = match $deployment_mode {
        "docker-compose" => "'docker_compose"
        "kubernetes" => "'kubernetes"
        "remote-ssh" | "ssh" => "'remote_ssh"
        "systemd" => "'systemd"
        _ => "'docker_compose"
    }

    let platform_nickel = $"# Platform Deployment Configuration (Nickel)
# Generated: (get-timestamp-iso8601)
# Profile: ($profile)
# Deployment Mode: ($deployment_mode)

let helpers = import \"../../schemas/platform/common/helpers.ncl\" in
let deployment_schema = import \"../../schemas/platform/deployment.ncl\" in
let defaults = import \"../../schemas/platform/defaults/deployment-defaults.ncl\" in

# Profile-specific overlay
let profile_overlay = import \"../../schemas/platform/defaults/deployment/($profile)-defaults.ncl\" in

# Compose: defaults + profile overlay + user customization
helpers.compose_config defaults profile_overlay {
  deployment = {
    mode = $deployment_mode_tag,
    location_type = 'local,
  },
  services = {
    orchestrator = {
      endpoint = \"http://localhost:9090/health\",
      timeout_seconds = 30,
    },
    control_center = {
      endpoint = \"http://localhost:3000/health\",
      timeout_seconds = 30,
    },
    kms_service = {
      endpoint = \"http://localhost:3001/health\",
      timeout_seconds = 30,
    },
  },
}
| deployment_schema.DeploymentConfig
"

    let result = (do { $platform_nickel | save -f $platform_config_path } | complete)
    ($result.exit_code == 0)
}

# Generate Nickel user preferences configuration from defaults
export def create-user-preferences-nickel [
    config_base: string
    profile: string = "developer"
] {
    let user_prefs_path = $"($config_base)/user_preferences.ncl"

    let user_prefs_nickel = $"# User Preferences Configuration (Nickel)
# Generated: (get-timestamp-iso8601)
# Profile: ($profile)

let helpers = import \"../../schemas/platform/common/helpers.ncl\" in
let prefs_schema = import \"../../schemas/platform/user_preferences.ncl\" in
let defaults = import \"../../schemas/platform/defaults/user_preferences-defaults.ncl\" in

# Profile-specific overlay (production has stricter defaults)
let profile_overlay = if \"($profile)\" == \"production\" then
  { confirm_delete = true, confirm_deploy = true }
else
  {}
in

# Compose: defaults + profile overlay
helpers.compose_config defaults profile_overlay {
  output_format = 'yaml,
  use_colors = true,
  confirm_delete = true,
  confirm_deploy = true,
  default_log_level = 'info,
  default_provider = \"local\",
  http_timeout_seconds = 30,
  editor = \"vim\",
}
| prefs_schema.UserPreferencesConfig
"

    let result = (do { $user_prefs_nickel | save -f $user_prefs_path } | complete)
    ($result.exit_code == 0)
}

# Generate Nickel provider configuration
export def create-provider-config-nickel [
    config_base: string
    provider: string
] {
    let provider_config_path = $"($config_base)/providers/($provider).ncl"

    let provider_nickel = (match $provider {
        "upcloud" => {
            $"# UpCloud Provider Configuration (Nickel)
# Generated: (get-timestamp-iso8601)

let provider_schema = import \"../../schemas/platform/provider.ncl\" in

{
  api_url = \"https://api.upcloud.com/1.3\",
  interface = \"API\",
  credentials_source = \"rustyvault://system/providers/upcloud\",
  timeout_seconds = 30,
}
| provider_schema.ProviderConfig
"
        }
        "aws" => {
            $"# AWS Provider Configuration (Nickel)
# Generated: (get-timestamp-iso8601)

let provider_schema = import \"../../schemas/platform/provider.ncl\" in

{
  region = \"us-east-1\",
  credentials_source = \"rustyvault://system/providers/aws\",
  timeout_seconds = 30,
}
| provider_schema.ProviderConfig
"
        }
        "hetzner" => {
            $"# Hetzner Provider Configuration (Nickel)
# Generated: (get-timestamp-iso8601)

let provider_schema = import \"../../schemas/platform/provider.ncl\" in

{
  api_url = \"https://api.hetzner.cloud/v1\",
  credentials_source = \"rustyvault://system/providers/hetzner\",
  timeout_seconds = 30,
}
| provider_schema.ProviderConfig
"
        }
        "local" => {
            $"# Local Provider Configuration (Nickel)
# Generated: (get-timestamp-iso8601)

let provider_schema = import \"../../schemas/platform/provider.ncl\" in

{
  base_path = \"/tmp/provisioning-local\",
  timeout_seconds = 10,
}
| provider_schema.ProviderConfig
"
        }
        _ => ""
    })

    if ($provider_nickel | is-empty) {
        return false
    }

    let result = (do { $provider_nickel | save -f $provider_config_path } | complete)
    ($result.exit_code == 0)
}

# Compose Nickel config from defaults, overlay, and user customizations
export def compose-nickel-from-defaults [
    config_type: string
    profile: string = "developer"
] {
    let schema_path = (get-nickel-schema-path $config_type)

    if ($schema_path | is-empty) {
        print-setup-error $"Unknown config type: ($config_type)"
        return {}
    }

    {
        schema_path: $schema_path
        profile: $profile
        defaults_available: true
    }
}

# Validate Nickel configuration using nickel typecheck
export def validate-nickel-config [
    config_path: path
] {
    if not ($config_path | path exists) {
        print-setup-warning $"Config file not found: ($config_path)"
        return false
    }

    # Check if nickel command is available
    let nickel_check = (do { which nickel } | complete)
    if ($nickel_check.exit_code != 0) {
        print-setup-warning "Nickel not installed - skipping typecheck validation"
        return true
    }

    # Run nickel typecheck
    let validation = (do { nickel typecheck $config_path } | complete)

    if ($validation.exit_code == 0) {
        return true
    } else {
        print-setup-error $"Nickel validation failed for ($config_path)"
        print-setup-error ($validation.stderr | default "Unknown error")
        return false
    }
}

# Export Nickel config to TOML (optional, for services that require TOML)
export def export-nickel-to-toml [
    ncl_path: path
    toml_path: path
] {
    if not ($ncl_path | path exists) {
        print-setup-error $"Nickel config not found: ($ncl_path)"
        return false
    }

    # Check if nickel command is available
    let nickel_check = (do { which nickel } | complete)
    if ($nickel_check.exit_code != 0) {
        print-setup-warning "Nickel not installed - cannot export to TOML"
        return false
    }

    # Run nickel export
    let export_result = (do { ^nickel export --format toml $ncl_path | save -f $toml_path } | complete)

    if ($export_result.exit_code == 0) {
        return true
    } else {
        print-setup-error $"Failed to export ($ncl_path) to TOML"
        return false
    }
}

# ============================================================================
# COMPLETE SYSTEM SETUP
# ============================================================================

# Execute complete system setup
export def setup-system-complete [
    setup_config: record
    --verbose = false
] {
    print-setup-header "Complete System Setup"
    print ""

    let config_base = (get-config-base-path)

    # Step 1: Ensure directories exist
    print-setup-info "Creating configuration directories..."
    if not (ensure-config-dirs) {
        print-setup-error "Failed to create configuration directories"
        return {
            success: false
            errors: ["Failed to create configuration directories"]
        }
    }
    print-setup-success "Configuration directories created"

    # Step 2: Create system configuration
    print-setup-info "Creating system configuration..."
    if not (create-system-config-file $config_base $setup_config.system_config) {
        print-setup-error "Failed to create system configuration"
        return {
            success: false
            errors: ["Failed to create system configuration"]
        }
    }
    print-setup-success "System configuration created"

    # Step 3: Create platform configuration
    print-setup-info "Creating platform services configuration..."
    if not (create-platform-config-file $config_base $setup_config) {
        print-setup-error "Failed to create platform configuration"
        return {
            success: false
            errors: ["Failed to create platform configuration"]
        }
    }
    print-setup-success "Platform services configuration created"

    # Step 4: Create user preferences
    print-setup-info "Creating user preferences..."
    if not (create-user-preferences-file $config_base {}) {
        print-setup-error "Failed to create user preferences"
        return {
            success: false
            errors: ["Failed to create user preferences"]
        }
    }
    print-setup-success "User preferences created"

    # Step 5: Setup provider configurations
    print-setup-info "Setting up provider configurations..."
    for provider in ($setup_config.providers? | default ["local"]) {
        if not (create-provider-config-file $config_base $provider) {
            print-setup-warning $"Failed to create provider config for ($provider)"
        }
    }
    print-setup-success "Provider configurations created"

    # Step 6: Create RustyVault bootstrap placeholder
    print-setup-info "Setting up RustyVault bootstrap key..."
    if not (create-rustyvault-bootstrap-placeholder $config_base) {
        print-setup-warning "Failed to create RustyVault bootstrap placeholder"
    }
    print-setup-success "RustyVault bootstrap key placeholder created"

    # Step 7: Create workspace registry
    print-setup-info "Creating workspace registry..."
    if not (create-workspace-registry $config_base) {
        print-setup-error "Failed to create workspace registry"
        return {
            success: false
            errors: ["Failed to create workspace registry"]
        }
    }
    print-setup-success "Workspace registry created"

    # Step 8: Setup Cedar policies
    print-setup-info "Setting up Cedar authorization policies..."
    if not (setup-cedar-policies $config_base) {
        print-setup-warning "Failed to setup Cedar policies"
    }
    print-setup-success "Cedar authorization policies configured"

    # Step 9: Create setup metadata
    print-setup-info "Finalizing setup..."
    let setup_metadata = {
        version: "1.0.0"
        completed_at: (get-timestamp-iso8601)
        setup_by: (get-current-user)
        setup_on_hostname: (get-system-hostname)
        deployment_mode: ($setup_config.deployment_mode? | default "docker-compose")
        providers: ($setup_config.providers? | default ["local"])
        security: ($setup_config.security? | default {})
    }

    let metadata_path = $"($config_base)/setup_metadata.yaml"
    let save_result = (save-config-yaml $metadata_path $setup_metadata)

    if not $save_result {
        print-setup-warning "Failed to save setup metadata"
    }

    print ""
    print-setup-success "System setup completed successfully!"
    print ""

    {
        success: true
        config_base: $config_base
        timestamp: (get-timestamp-iso8601)
        setup_config: $setup_config
    }
}

# Run interactive setup wizard with all steps
export def run-interactive-setup [
    --verbose = false
] {
    let wizard_result = (run-setup-wizard --verbose=$verbose)

    if not $wizard_result.completed {
        return {
            success: false
            reason: "Setup wizard cancelled by user"
        }
    }

    setup-system-complete $wizard_result --verbose=$verbose
}

# Run setup with defaults (no interaction)
export def run-setup-defaults [
    --verbose = false
] {
    let defaults = (run-setup-with-defaults)

    setup-system-complete $defaults --verbose=$verbose
}

# Run minimal setup
export def run-setup-minimal [
    --verbose = false
] {
    let minimal = (run-minimal-setup)

    setup-system-complete $minimal --verbose=$verbose
}

# ============================================================================
# SETUP INFORMATION
# ============================================================================

# Print setup status
export def print-setup-status [] {
    let config_base = (get-config-base-path)

    print ""
    print "╔═══════════════════════════════════════════════════════════════╗"
    print "║            PROVISIONING SYSTEM SETUP STATUS                  ║"
    print "╚═══════════════════════════════════════════════════════════════╝"
    print ""
    print $"Configuration Base: ($config_base)"
    print ""

    if ($"($config_base)/system.toml" | path exists) {
        print "✅ System configuration found"
    } else {
        print "❌ System configuration NOT found"
    }

    if ($"($config_base)/platform/deployment.toml" | path exists) {
        print "✅ Platform configuration found"
    } else {
        print "❌ Platform configuration NOT found"
    }

    if ($"($config_base)/user_preferences.toml" | path exists) {
        print "✅ User preferences found"
    } else {
        print "❌ User preferences NOT found"
    }

    if ($"($config_base)/workspaces_registry.yaml" | path exists) {
        print "✅ Workspace registry found"
    } else {
        print "❌ Workspace registry NOT found"
    }

    if ($"($config_base)/cedar-policies" | path exists) {
        print "✅ Cedar policies directory found"
    } else {
        print "❌ Cedar policies directory NOT found"
    }

    print ""
    print "═══════════════════════════════════════════════════════════════"
    print ""
}
