#!/usr/bin/env nu
# VAPORA Deployment Pipeline Orchestration
# Handles configuration generation, validation, and deployment to all platforms
# Version: 1.0.0

def main [
    --mode: string = "multiuser"
    --output-dir: string = "dist"
    --target: string = "docker"
    --validate-only: bool = false
    --dry-run: bool = false
] {
    let timestamp = (date now | format date '%Y%m%d-%H%M%S')
    let log_file = ($output_dir | path join $"deploy-($timestamp).log")

    # Create output directory
    do {
        mkdir ($output_dir | path expand)
    } | complete | if $in.exit_code != 0 {
        error make {msg: $"Failed to create output directory: ($in.stderr)"}
    }

    print $"🚀 VAPORA Deployment Pipeline - Mode: ($mode), Target: ($target)"
    print $"📝 Logging to: ($log_file)"
    print ""

    # Step 1: Generate configuration
    print "Step 1️⃣  - Generating configuration from Nickel..."
    let config_json = (generate-config $mode $output_dir)
    if $config_json == null {
        error make {msg: "Configuration generation failed"}
    }
    print "✓ Configuration generated"
    print ""

    # Step 2: Validate configuration
    print "Step 2️⃣  - Validating configuration..."
    let validation = (validate-config $config_json)
    if not $validation.valid {
        error make {msg: $"Validation failed: ($validation.errors | str join ', ')"}
    }
    print "✓ Configuration valid"
    print ""

    # Step 3: Render templates based on target
    print "Step 3️⃣  - Rendering output templates..."
    let rendered = (render-templates $config_json $mode $output_dir $target)
    if not $rendered {
        error make {msg: "Template rendering failed"}
    }
    print "✓ Templates rendered"
    print ""

    # Step 4: Validate rendered outputs
    print "Step 4️⃣  - Validating rendered outputs..."
    let output_validation = (validate-outputs $output_dir $target)
    if not $output_validation.valid {
        error make {msg: $"Output validation failed: ($output_validation.errors | str join ', ')"}
    }
    print "✓ Outputs validated"
    print ""

    if $validate_only {
        print "✅ Validation complete (--validate-only specified)"
        return
    }

    # Step 5: Deploy based on target
    print "Step 5️⃣  - Deploying..."
    match $target {
        "docker" => {
            print "📦 Deploying to Docker Compose..."
            deploy-docker $mode $output_dir $dry_run
        }
        "kubernetes" => {
            print "☸️  Deploying to Kubernetes..."
            deploy-kubernetes $mode $output_dir $dry_run
        }
        "both" => {
            print "📦 Deploying to Docker Compose..."
            deploy-docker $mode $output_dir $dry_run
            print "☸️  Deploying to Kubernetes..."
            deploy-kubernetes $mode $output_dir $dry_run
        }
        _ => {
            error make {msg: $"Unknown target: ($target). Use 'docker', 'kubernetes', or 'both'"}
        }
    }

    print ""
    print "✅ Deployment complete!"
    print $"Outputs saved to: ($output_dir)"
}

def generate-config [mode: string, output_dir: string] {
    let config_file = $"schemas/platform/configs/vapora-($mode).ncl"

    if not ($config_file | path exists) {
        error make {msg: $"Config not found: ($config_file)"}
    }

    let output_path = ($output_dir | path join $"config-($mode).json")

    let result = do {
        nickel export $config_file
    } | complete

    if $result.exit_code != 0 {
        error make {msg: $"Nickel export failed: ($result.stderr)"}
    }

    let json_output = $result.stdout

    do {
        $json_output | save -f $output_path
    } | complete | if $in.exit_code != 0 {
        error make {msg: $"Failed to save config: ($in.stderr)"}
    }

    $output_path
}

def validate-config [config_path: string] {
    let config = do {
        open $config_path
    } | complete

    if $config.exit_code != 0 {
        return {
            valid: false
            errors: [
                $"Failed to parse config: ($config.stderr)"
            ]
        }
    }

    let parsed = ($config.stdout | from json)
    let errors = []

    # Validate required fields
    let required_fields = [
        "deployment_mode"
        "backend"
        "agents"
        "llm_router"
        "database"
        "frontend"
    ]

    let missing_fields = $required_fields | where { |field|
        not ($parsed | has $field)
    }

    if ($missing_fields | length) > 0 {
        return {
            valid: false
            errors: [
                $"Missing required fields: ($missing_fields | str join ', ')"
            ]
        }
    }

    # Validate deployment mode
    let valid_modes = ["solo", "multiuser", "enterprise"]
    if not ($valid_modes | any { |mode| $mode == $parsed.deployment_mode }) {
        return {
            valid: false
            errors: [
                $"Invalid deployment_mode: ($parsed.deployment_mode)"
            ]
        }
    }

    {valid: true, errors: []}
}

def render-templates [config_path: string, mode: string, output_dir: string, target: string] {
    let config = (open $config_path)

    # Render TOML
    print "  → Rendering TOML configuration..."
    let toml_result = do {
        jinja2 schemas/platform/templates/configs/vapora.toml.j2 $config_path
    } | complete

    if $toml_result.exit_code != 0 {
        print $"  ✗ TOML rendering failed: ($toml_result.stderr)"
        return false
    }

    do {
        $toml_result.stdout | save -f ($output_dir | path join $"vapora-($mode).toml")
    } | complete | if $in.exit_code != 0 {
        return false
    }
    print "  ✓ TOML"

    # Render YAML
    print "  → Rendering YAML configuration..."
    let yaml_result = do {
        jinja2 schemas/platform/templates/configs/vapora.yaml.j2 $config_path
    } | complete

    if $yaml_result.exit_code != 0 {
        print $"  ✗ YAML rendering failed: ($yaml_result.stderr)"
        return false
    }

    do {
        $yaml_result.stdout | save -f ($output_dir | path join $"vapora-($mode).yaml")
    } | complete | if $in.exit_code != 0 {
        return false
    }
    print "  ✓ YAML"

    # Render Kubernetes templates if needed
    if ($target == "kubernetes") or ($target == "both") {
        print "  → Rendering Kubernetes ConfigMap..."
        let cm_result = do {
            jinja2 schemas/platform/templates/kubernetes/configmap.yaml.j2 $config_path
        } | complete

        if $cm_result.exit_code != 0 {
            print $"  ✗ ConfigMap rendering failed: ($cm_result.stderr)"
            return false
        }

        do {
            $cm_result.stdout | save -f ($output_dir | path join "configmap.yaml")
        } | complete | if $in.exit_code != 0 {
            return false
        }
        print "  ✓ ConfigMap"

        print "  → Rendering Kubernetes Deployment..."
        let deploy_result = do {
            jinja2 schemas/platform/templates/kubernetes/deployment.yaml.j2 $config_path
        } | complete

        if $deploy_result.exit_code != 0 {
            print $"  ✗ Deployment rendering failed: ($deploy_result.stderr)"
            return false
        }

        do {
            $deploy_result.stdout | save -f ($output_dir | path join "deployment.yaml")
        } | complete | if $in.exit_code != 0 {
            return false
        }
        print "  ✓ Deployment"
    }

    # Render Docker Compose if needed
    if ($target == "docker") or ($target == "both") {
        print "  → Rendering Docker Compose..."
        let dc_result = do {
            jinja2 schemas/platform/templates/docker-compose/docker-compose.yaml.j2 $config_path
        } | complete

        if $dc_result.exit_code != 0 {
            print $"  ✗ Docker Compose rendering failed: ($dc_result.stderr)"
            return false
        }

        do {
            $dc_result.stdout | save -f ($output_dir | path join "docker-compose.yml")
        } | complete | if $in.exit_code != 0 {
            return false
        }
        print "  ✓ Docker Compose"
    }

    true
}

def validate-outputs [output_dir: string, target: string] {
    let errors = []

    # Validate YAML files
    let yaml_files = if ($target == "docker") {
        ["vapora-solo.yaml", "vapora-multiuser.yaml", "vapora-enterprise.yaml"]
    } else if ($target == "kubernetes") {
        ["configmap.yaml", "deployment.yaml"]
    } else {
        ["vapora-solo.yaml", "configmap.yaml", "deployment.yaml"]
    }

    $yaml_files | each { |file|
        let path = ($output_dir | path join $file)
        if not ($path | path exists) {
            $errors | append $"Missing file: ($file)"
        } else {
            let validate = do {
                yq eval '.' $path
            } | complete

            if $validate.exit_code != 0 {
                $errors | append $"Invalid YAML in ($file): ($validate.stderr)"
            }
        }
    }

    {
        valid: ($errors | length) == 0
        errors: $errors
    }
}

def deploy-docker [mode: string, output_dir: string, dry_run: bool] {
    let compose_file = ($output_dir | path join "docker-compose.yml")

    if not ($compose_file | path exists) {
        error make {msg: "Docker Compose file not found"}
    }

    print "  📍 Docker Compose file: $compose_file"

    if $dry_run {
        print "  🔍 [DRY RUN] Would execute: docker compose -f $compose_file up -d"
        return
    }

    print "  🚀 Starting Docker Compose services..."
    let result = do {
        docker compose -f $compose_file up -d
    } | complete

    if $result.exit_code != 0 {
        error make {msg: $"Docker Compose failed: ($result.stderr)"}
    }

    print "  ✓ Services started"
    print ""
    print "  📊 Running services:"
    do {
        docker compose -f $compose_file ps
    } | complete | if $in.exit_code == 0 {
        print $in.stdout
    }
}

def deploy-kubernetes [mode: string, output_dir: string, dry_run: bool] {
    let configmap_file = ($output_dir | path join "configmap.yaml")
    let deployment_file = ($output_dir | path join "deployment.yaml")

    if not ($configmap_file | path exists) {
        error make {msg: "Kubernetes ConfigMap not found"}
    }

    if not ($deployment_file | path exists) {
        error make {msg: "Kubernetes Deployment not found"}
    }

    # Ensure namespace exists
    if $dry_run {
        print "  🔍 [DRY RUN] Would create namespace: vapora"
    } else {
        do {
            kubectl create namespace vapora --dry-run=client -o yaml | kubectl apply -f -
        } | complete | if $in.exit_code != 0 {
            print "  ⚠️  Namespace creation (may already exist)"
        }
    }

    # Apply ConfigMap
    print "  📍 Applying ConfigMap..."
    if $dry_run {
        print "  🔍 [DRY RUN] Would apply: ($configmap_file)"
    } else {
        let cm_result = do {
            kubectl apply -f $configmap_file
        } | complete

        if $cm_result.exit_code != 0 {
            error make {msg: $"ConfigMap deployment failed: ($cm_result.stderr)"}
        }
        print "  ✓ ConfigMap applied"
    }

    # Apply Deployments
    print "  📍 Applying Deployments..."
    if $dry_run {
        print "  🔍 [DRY RUN] Would apply: ($deployment_file)"
    } else {
        let deploy_result = do {
            kubectl apply -f $deployment_file
        } | complete

        if $deploy_result.exit_code != 0 {
            error make {msg: $"Deployment failed: ($deploy_result.stderr)"}
        }
        print "  ✓ Deployments applied"
    }

    print ""
    print "  📊 Deployment status:"
    do {
        kubectl get deployment -n vapora -o wide
    } | complete | if $in.exit_code == 0 {
        print $in.stdout
    }
}

# Run main function
main
