# Health Check Module
# Deep health validation for provisioning platform configuration and state

use std log
use ../config/accessor.nu *
use ../user/config.nu *

# Check health of configuration files
def check-config-files [] {
    mut issues = []
    let user_config_path = (get-user-config-path)

    # Check user_config.yaml
    if not ($user_config_path | path exists) {
        $issues = ($issues | append "user_config.yaml not found")
    }

    # Check active workspace config if user config exists
    if ($user_config_path | path exists) {
        let user_config = (load-user-config)
        let active = ($user_config.active_workspace? | default null)

        if $active != null {
            let workspace = ($user_config.workspaces | where name == $active | first)
            let ws_path = ($workspace.path? | default "")
            let config_path = ($ws_path | path join "config" | path join "provisioning.yaml")

            if not ($config_path | path exists) {
                $issues = ($issues | append $"Workspace config not found: ($config_path)")
            }
        }
    }

    {
        check: "Configuration Files"
        status: (if ($issues | is-empty) { "✅ Healthy" } else { "❌ Issues Found" })
        issues: $issues
        recommendation: (if ($issues | is-not-empty) {
            "Missing config files. Run: provisioning workspace init <name> to create workspace"
        } else {
            "All configuration files present"
        })
    }
}

# Check workspace structure integrity
def check-workspace-structure [] {
    mut issues = []

    let user_config = (load-user-config)
    let active = ($user_config.active_workspace? | default null)

    if $active == null {
        $issues = ($issues | append "No active workspace configured")
    } else {
        let workspace = ($user_config.workspaces | where name == $active | first)
        let ws_path = ($workspace.path? | default "")

        if not ($ws_path | path exists) {
            $issues = ($issues | append $"Workspace path does not exist: ($ws_path)")
        } else {
            # Check required directories
            let required_dirs = ["infra" "config" "extensions" "runtime"]

            for dir in $required_dirs {
                let dir_path = ($ws_path | path join $dir)
                if not ($dir_path | path exists) {
                    $issues = ($issues | append $"Missing required directory: ($dir)")
                }
            }

            # Check config subdirectories
            let config_dirs = ["providers" "platform"]
            for dir in $config_dirs {
                let dir_path = ($ws_path | path join "config" | path join $dir)
                if not ($dir_path | path exists) {
                    $issues = ($issues | append $"Missing config directory: config/($dir)")
                }
            }
        }
    }

    {
        check: "Workspace Structure"
        status: (if ($issues | is-empty) { "✅ Healthy" } else { "❌ Issues Found" })
        issues: $issues
        recommendation: (if ($issues | is-not-empty) {
            "Workspace directories missing. Run: provisioning workspace init <name> to create structure"
        } else {
            "Workspace structure complete"
        })
    }
}

# Check infrastructure state
def check-infrastructure-state [] {
    mut issues = []
    mut warnings = []

    let user_config = (load-user-config)
    let active = ($user_config.active_workspace? | default null)

    if $active != null {
        let workspace = ($user_config.workspaces | where name == $active | first)
        let ws_path = ($workspace.path? | default "")
        let infra_path = ($ws_path | path join "infra")

        if ($infra_path | path exists) {
            let infra_dirs = (ls $infra_path | where type == dir | length)

            if $infra_dirs == 0 {
                $warnings = ($warnings | append "No infrastructure definitions found")
            }

            # Check for orphaned state files
            let state_path = ($ws_path | path join "runtime" | path join "state")
            if ($state_path | path exists) {
                let state_files = (ls $state_path --all
                    | where name =~ r"\.state$"
                    | length)

                if $state_files > 0 {
                    $warnings = ($warnings | append $"($state_files) state files found - may indicate previous deployments")
                }
            }
        } else {
            $warnings = ($warnings | append "Infrastructure directory does not exist")
        }
    }

    {
        check: "Infrastructure State"
        status: (if ($issues | is-empty) {
            if ($warnings | is-empty) { "✅ Healthy" } else { "⚠️ Warnings" }
        } else {
            "❌ Issues Found"
        })
        issues: ($issues | append $warnings)
        recommendation: (if ($issues | is-not-empty) or ($warnings | is-not-empty) {
            "No infrastructure defined. Run: provisioning generate infra --new <name> to create"
        } else {
            "Infrastructure configured"
        })
    }
}

# Check platform services connectivity
def check-platform-connectivity [] {
    mut issues = []
    mut warnings = []

    # Check orchestrator
    let orchestrator_url = (config-get "platform.orchestrator.url" "http://localhost:9011")

    let orchestrator_response = (do -i {
        http get $"($orchestrator_url)/health" --max-time 2sec
    })
    let orchestrator_healthy = ($orchestrator_response != null)

    if not $orchestrator_healthy {
        $warnings = ($warnings | append "Orchestrator not responding - workflows will not be available")
    }

    # Check control center
    let control_center_port = config-get "control_center.port" 8080

    let control_center_response = (do -i {
        http get $"http://localhost:($control_center_port)/health" --max-time 1sec
    })
    let control_center_healthy = ($control_center_response != null)

    if not $control_center_healthy {
        $warnings = ($warnings | append "Control Center not responding - web UI will not be available")
    }

    # Build recommendation based on what's not running
    let recommendation = if ($warnings | is-empty) {
        "All services responding"
    } else {
        let not_running = []
        let not_running = if not $orchestrator_healthy {
            $not_running | append "orchestrator"
        } else {
            $not_running
        }
        let not_running = if not $control_center_healthy {
            $not_running | append "control-center"
        } else {
            $not_running
        }

        $"Platform services not running: ($not_running | str join ', '). These services are optional for basic provisioning operations."
    }

    {
        check: "Platform Services"
        status: (if ($issues | is-empty) {
            if ($warnings | is-empty) { "✅ Healthy" } else { "⚠️ Warnings" }
        } else {
            "❌ Issues Found"
        })
        issues: ($issues | append $warnings)
        recommendation: $recommendation
    }
}

# Check Nickel schemas validity
def check-nickel-schemas [] {
    mut issues = []
    mut warnings = []

    let nickel_path = config-get "paths.nickel" "provisioning/nickel"

    if not ($nickel_path | path exists) {
        $issues = ($issues | append "Nickel directory not found")
    } else {
        # Check for main schema files
        let required_schemas = [
            "main.ncl"
            "settings.ncl"
            "lib.ncl"
            "dependencies.ncl"
        ]

        for schema in $required_schemas {
            let schema_path = ($nickel_path | path join $schema)
            if not ($schema_path | path exists) {
                $warnings = ($warnings | append $"Schema file not found: ($schema)")
            }
        }

        # Try to compile a simple Nickel file
        let nickel_bin = (which nickel | get path.0? | default "")
        if ($nickel_bin | is-not-empty) {
            do -i {
                ^nickel fmt --check $nickel_path e> /dev/null o> /dev/null
            }

            if ($env.LAST_EXIT_CODE? | default 1) != 0 {
                $warnings = ($warnings | append "Nickel format check reported issues")
            }
        } else {
            $warnings = ($warnings | append "Nickel CLI not available - cannot validate schemas")
        }
    }

    {
        check: "Nickel Schemas"
        status: (if ($issues | is-empty) {
            if ($warnings | is-empty) { "✅ Healthy" } else { "⚠️ Warnings" }
        } else {
            "❌ Issues Found"
        })
        issues: ($issues | append $warnings)
        recommendation: (if ($issues | is-not-empty) or ($warnings | is-not-empty) {
            "Nickel schemas missing. Ensure provisioning/schemas/ directory exists"
        } else {
            "Schemas validated"
        })
    }
}

# Check security configuration
def check-security-config [] {
    mut issues = []
    mut warnings = []

    # Check if encryption is configured
    let kms_enabled = config-get "kms.enabled" false

    if not $kms_enabled {
        $warnings = ($warnings | append "KMS not enabled - secrets will not be encrypted")
    }

    # Check authentication
    let auth_enabled = config-get "auth.enabled" false

    if not $auth_enabled {
        $warnings = ($warnings | append "Authentication not enabled - platform access is unprotected")
    }

    # Check if SOPS/Age is available
    let sops_bin = (which sops | get path.0? | default "")
    let age_bin = (which age | get path.0? | default "")

    if ($sops_bin | is-empty) {
        $warnings = ($warnings | append "SOPS not installed - encrypted config editing will not work")
    }

    if ($age_bin | is-empty) {
        $warnings = ($warnings | append "Age not installed - encryption will not work")
    }

    {
        check: "Security Configuration"
        status: (if ($issues | is-empty) {
            if ($warnings | is-empty) { "✅ Healthy" } else { "⚠️ Warnings" }
        } else {
            "❌ Issues Found"
        })
        issues: ($issues | append $warnings)
        recommendation: (if ($warnings | is-not-empty) {
            "Security optional. Install: brew install sops age (encryption tools)"
        } else {
            "Security configured"
        })
    }
}

# Check provider credentials
def check-provider-credentials [] {
    mut issues = []
    mut warnings = []

    # Check UpCloud credentials
    let upcloud_user = ($env.UPCLOUD_USERNAME? | default "")
    let upcloud_pass = ($env.UPCLOUD_PASSWORD? | default "")

    if ($upcloud_user | is-empty) or ($upcloud_pass | is-empty) {
        $warnings = ($warnings | append "UpCloud credentials not configured")
    }

    # Check AWS credentials
    let aws_key = ($env.AWS_ACCESS_KEY_ID? | default "")
    let aws_secret = ($env.AWS_SECRET_ACCESS_KEY? | default "")

    if ($aws_key | is-empty) or ($aws_secret | is-empty) {
        $warnings = ($warnings | append "AWS credentials not configured")
    }

    {
        check: "Provider Credentials"
        status: (if ($issues | is-empty) {
            if ($warnings | is-empty) { "✅ Healthy" } else { "⚠️ Warnings" }
        } else {
            "❌ Issues Found"
        })
        issues: ($issues | append $warnings)
        recommendation: (if ($warnings | is-not-empty) {
            "Credentials not set. Export: UPCLOUD_USERNAME/PASSWORD or AWS_ACCESS_KEY_ID/SECRET"
        } else {
            "Credentials configured"
        })
    }
}

# Main health check command
# Comprehensive health validation of platform configuration and state
export def "provisioning health" [] {
    print $"(ansi yellow_bold)Provisioning Platform Health Check(ansi reset)\n"

    mut health_checks = []

    # Run all health checks
    $health_checks = ($health_checks | append (check-config-files))
    $health_checks = ($health_checks | append (check-workspace-structure))
    $health_checks = ($health_checks | append (check-infrastructure-state))
    $health_checks = ($health_checks | append (check-platform-connectivity))
    $health_checks = ($health_checks | append (check-nickel-schemas))
    $health_checks = ($health_checks | append (check-security-config))
    $health_checks = ($health_checks | append (check-provider-credentials))

    # Display results
    print ($health_checks | select check status recommendation)
    print ""

    # Show detailed issues
    let checks_with_issues = ($health_checks | where {|c| ($c.issues | is-not-empty)})

    if ($checks_with_issues | is-not-empty) {
        print $"(ansi red_bold)Issues Found:(ansi reset)\n"

        for check in $checks_with_issues {
            print $"(ansi red_bold)($check.check):(ansi reset)"
            for issue in $check.issues {
                print $"  • ($issue)"
            }
            print ""
        }
    } else {
        print $"(ansi green_bold)✅ All health checks passed!(ansi reset)\n"
    }

    $health_checks | select check status recommendation
}

# Get health summary (machine-readable)
export def "provisioning health-json" [] {
    let health_checks = [
        (check-config-files)
        (check-workspace-structure)
        (check-infrastructure-state)
        (check-platform-connectivity)
        (check-nickel-schemas)
        (check-security-config)
        (check-provider-credentials)
    ]

    let total = ($health_checks | length)
    let healthy = ($health_checks | where status =~ "✅" | length)
    let warnings = ($health_checks | where status =~ "⚠️" | length)
    let failing = ($health_checks | where status =~ "❌" | length)

    {
        timestamp: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
        summary: {
            total: $total
            healthy: $healthy
            warnings: $warnings
            failing: $failing
            health_score: (($healthy / $total) * 100 | math round)
        }
        checks: $health_checks
        production_ready: ($failing == 0 and $warnings == 0)
    }
}
