#!/usr/bin/env nu

# Install and Deploy Platform Services
# Orchestrates full deployment workflow: config generation → validation → deployment
# Supports multiple backends: local, docker, kubernetes
# Usage: nu install-services.nu orchestrator solo
# Usage: nu install-services.nu all multiuser --docker
# Usage: nu install-services.nu all enterprise --kubernetes --namespace prod

use ansi.nu
use external.nu
use paths.nu

export def main [
    service: string              # Service: orchestrator | control-center | mcp-server | vault-service | extension-registry | rag | ai-service | provisioning-daemon | all
    mode: string                 # Mode: solo | multiuser | cicd | enterprise
    --docker = false       # Deploy to Docker
    --kubernetes = false   # Deploy to Kubernetes
    --namespace: string = "provisioning"  # Kubernetes namespace
    --skip-config = false  # Skip config generation
    --skip-validation = false  # Skip validation
    --no-compose = false   # Don't render Docker Compose
]: nothing -> nothing {
    # Validate mode
    paths validate-mode $mode

    # Determine services to install
    let services_to_install: list<string> = if $service == "all" {
        ["orchestrator", "control-center", "mcp-server", "vault-service", "extension-registry", "rag", "ai-service", "provisioning-daemon"]
    } else {
        paths validate-service $service
        [$service]
    }

    section "Platform Services Deployment"
    print $"Mode:     ($mode)"
    print $"Services: ($services_to_install | str join ', ')"
    print $"Docker:   ($docker)"
    print $"K8s:      ($kubernetes)"
    print $"Namespace: ($namespace)"
    print ""

    # Phase 1: Configuration Generation
    if not $skip_config {
        section "Phase 1: Configuration Generation"

        for svc in $services_to_install {
            print ""
            print-working $"Generating config for ($svc)..."

            let result: record<exit_code: int, stdout: string, stderr: string> = do {
                ^nu (paths scripts-path) / "generate-configs.nu" $svc $mode
            } | complete

            if $result.exit_code != 0 {
                print-error $"Failed to generate config for ($svc)"
                print $result.stderr
                exit 1
            }

            print-success $"Config generated for ($svc)"
        }

        print ""
    }

    # Phase 2: Validation
    if not $skip_validation {
        section "Phase 2: Configuration Validation"

        for svc in $services_to_install {
            let config_path: string = (paths get-output-config-path $svc $mode)

            if not (external file-exists $config_path) {
                print-warning $"Config not found: ($config_path)"
                continue
            }

            print-validate $"Validating ($svc)..."

            let result: record<exit_code: int, stdout: string, stderr: string> = do {
                ^nu (paths scripts-path) / "validate-config.nu" $config_path
            } | complete

            if $result.exit_code != 0 {
                print-error $"Validation failed for ($svc)"
                print $result.stderr
                exit 1
            }
        }

        print ""
    }

    # Phase 3: Rendering Deployment Artifacts
    section "Phase 3: Rendering Deployment Artifacts"

    if $docker and not $no_compose {
        print-docker "Rendering Docker Compose..."

        let result: record<exit_code: int, stdout: string, stderr: string> = do {
            ^nu (paths scripts-path) / "render-docker-compose.nu" $mode
        } | complete

        if $result.exit_code != 0 {
            print-error "Failed to render Docker Compose"
            print $result.stderr
            # Continue anyway, Docker rendering is optional
        }
    }

    if $kubernetes {
        print-k8s "Rendering Kubernetes manifests..."

        let result: record<exit_code: int, stdout: string, stderr: string> = do {
            ^nu (paths scripts-path) / "render-kubernetes.nu" $mode --namespace $namespace
        } | complete

        if $result.exit_code != 0 {
            print-error "Failed to render Kubernetes manifests"
            print $result.stderr
            # Continue anyway, K8s rendering is optional
        }
    }

    print ""

    # Phase 4: Deployment (if requested)
    if $docker {
        deploy-docker $mode
    } else if $kubernetes {
        deploy-kubernetes $mode $namespace
    }

    print ""
    section "Installation Summary"
    print-success "Phase 8 deployment workflow completed"
    print ""
    print "Generated configurations are ready for use:"
    for svc in $services_to_install {
        let config_path: string = (paths get-output-config-path $svc $mode)
        next-step $config_path
    }

    print ""
    section "Next Steps"
    next-step "Test configuration: cargo run -p orchestrator -- --config provisioning/config/runtime/generated/orchestrator.($mode).toml"
    next-step "Full deployment: See provisioning/platform/infrastructure/ for Docker Compose and Kubernetes manifests"
}

def deploy-docker [mode: string]: nothing -> nothing {
    section "Phase 4: Docker Deployment"

    let compose_file: string = "provisioning/platform/infrastructure/docker/docker-compose." + $mode + ".yml"

    if not (external file-exists $compose_file) {
        print-warning $"Docker Compose file not found: ($compose_file)"
        print-info "Run with --docker flag to render Compose files first"
        return
    }

    print-docker $"Deploying with Docker Compose: ($compose_file)"

    let result: record<exit_code: int, stdout: string, stderr: string> = (external run-cmd "docker-compose" ["-f", $compose_file, "up", "-d"])

    if $result.exit_code != 0 {
        print-error "Docker Compose deployment failed"
        print $result.stderr
        exit 1
    }

    print-success "Docker Compose deployment completed"

    print ""
    next-step "View logs:    docker-compose -f ($compose_file) logs -f"
    next-step "Stop services: docker-compose -f ($compose_file) down"
    next-step "Status:       docker-compose -f ($compose_file) ps"
}

def deploy-kubernetes [mode: string, namespace: string]: nothing -> nothing {
    section "Phase 4: Kubernetes Deployment"

    let manifest_dir: string = "provisioning/platform/infrastructure/kubernetes/" + $mode

    if not (external dir-exists $manifest_dir) {
        print-warning $"Kubernetes manifest directory not found: ($manifest_dir)"
        print-info "Run with --kubernetes flag to render manifests first"
        return
    }

    print-k8s $"Creating namespace: ($namespace)"

    let ns_result: record<exit_code: int, stdout: string, stderr: string> = (external run-cmd "kubectl" ["create", "namespace", $namespace])

    # Namespace may already exist, that's ok
    if $ns_result.exit_code != 0 and not ($ns_result.stderr | str contains "already exists") {
        print-warning $"Namespace creation: ($ns_result.stderr)"
    }

    print-k8s $"Deploying Kubernetes manifests from: ($manifest_dir)"

    let deploy_result: record<exit_code: int, stdout: string, stderr: string> = (external run-cmd "kubectl" ["apply", "-f", $manifest_dir, "-n", $namespace])

    if $deploy_result.exit_code != 0 {
        print-error "Kubernetes deployment failed"
        print $deploy_result.stderr
        exit 1
    }

    print-success "Kubernetes deployment completed"

    print ""
    next-step "View deployments:  kubectl get deployments -n ($namespace)"
    next-step "View services:     kubectl get svc -n ($namespace)"
    next-step "View pods:         kubectl get pods -n ($namespace)"
    next-step "View logs:         kubectl logs -n ($namespace) -l app=orchestrator -f"
}
