# Workspace Configuration Management Commands
# Provides commands to view, edit, validate, and manage workspace configurations

use ../user/config.nu [list-workspaces get-active-workspace get-workspace-path]
use ../utils/nickel_processor.nu [ncl-eval-soft]

# Get active workspace context or load by name
def get-workspace-context [
  workspace_name?: string
] {
  if ($workspace_name | is-empty) {
    let active = (get-active-workspace)
    if ($active | is-empty) {
      print "❌ No active workspace found. Use 'provisioning workspace activate <name>'"
      exit 1
    }
    let path = (get-workspace-path $active)
    {
      name: $active
      path: $path
    }
  } else {
    let contexts = (list-workspaces)

    # First try to match by name
    let found = ($contexts | where name == $workspace_name | first)

    if ($found | is-empty) {
      # Try to resolve as a path (could be full, relative, or just a directory name)
      # First try as-is (could be absolute path)
      let input_as_path = if ($workspace_name | path exists) {
        $workspace_name | path expand
      } else {
        # Try as relative path from current directory
        let rel_path = ($env.PWD | path join $workspace_name)
        if ($rel_path | path exists) {
          $rel_path | path expand
        } else {
          # If it looks like an absolute path, try as-is; otherwise try expanding
          $workspace_name | path expand
        }
      }

      # Check if this path exists
      let path_exists = ($input_as_path | path exists)

      if $path_exists {
        # Found a directory, now try to match it against registered workspaces
        let found_by_path = ($contexts | where (path | path expand) == $input_as_path | first)

        if ($found_by_path | is-not-empty) {
          return $found_by_path
        }

        # Path exists but is not registered - check if it looks like a workspace
        # Try both .ncl and .yaml config files
        let config_file_nickel = ($input_as_path | path join "config" | path join "provisioning.ncl")
        let config_file_yaml = ($input_as_path | path join "config" | path join "provisioning.yaml")
        if (($config_file_nickel | path exists) or ($config_file_yaml | path exists)) {
          # It's a valid workspace directory, return it
          return {
            name: ($input_as_path | path basename)
            path: $input_as_path
          }
        }
      }

      # Try exact path match on registered paths (for backward compatibility)
      let found_by_exact_path = ($contexts | where path == $workspace_name | first)
      if ($found_by_exact_path | is-not-empty) {
        return $found_by_exact_path
      }

      # Not found by any method
      print $"❌ Workspace '($workspace_name)' not found"
      exit 1
    }
    $found
  }
}

# Show complete workspace configuration
export def "workspace-config-show" [
  workspace_name?: string
  --format: string = "yaml"  # yaml, json, toml, nickel
] {
  let workspace = (get-workspace-context $workspace_name)

  # Load complete config - try Nickel first, fallback to YAML
  let config_dir = ($workspace.path | path join "config")
  let decl_file = ($config_dir | path join "provisioning.ncl")
  let yaml_file = ($config_dir | path join "provisioning.yaml")

  # Try Nickel first, but fallback to YAML if compilation fails (silently)
  let config_file = if ($decl_file | path exists) {
    # Try Nickel compilation (silently - we have YAML fallback)
    let ncl_ok = (ncl-eval-soft $decl_file [] null | is-not-empty)
    if $ncl_ok {
      $decl_file
    } else if ($yaml_file | path exists) {
      # Silently fallback to YAML
      $yaml_file
    } else {
      $decl_file
    }
  } else if ($yaml_file | path exists) {
    $yaml_file
  } else {
    null
  }

  if ($config_file | is-empty) {
    print "❌ No workspace configuration found (neither .ncl nor .yaml)"
    exit 1
  }

  # Load the config file
  let config = if ($config_file | str ends-with ".ncl") {
    # Load Nickel config (outputs YAML by default)
    # Check if nickel.mod exists in the same directory - if so, use 'nickel export' from that directory
    let file_dir = ($config_file | path dirname)
    let file_name = ($config_file | path basename)
    let decl_mod_exists = (($file_dir | path join "nickel.mod") | path exists)

    let parsed = if $decl_mod_exists {
      # Package-based configs: must run from config dir so nickel.mod resolves correctly
      let res = (do { ^sh -c $"cd '($file_dir)' && nickel export ($file_name) --format json" } | complete)
      if ($res.stdout | is-not-empty) { $res.stdout | from json } else { null }
    } else {
      ncl-eval-soft $config_file [] null
    }

    if ($parsed | is-empty) {
      print "❌ Failed to load Nickel config: empty output"
      exit 1
    }
    # Extract workspace_config if present
    if (($parsed | columns) | any { |col| $col == "workspace_config" }) {
      $parsed.workspace_config
    } else {
      $parsed
    }
  } else {
    # Load YAML config - open handles parsing automatically
    open $config_file
  }

  # Determine config format type for display
  let config_type = if ($config_file | str ends-with ".ncl") { "Nickel" } else { "YAML" }

  # Output with format specified
  match $format {
    "yaml" => {
      print $"Configuration ($config_type): ($config_file)"
      print ""
      ($config | to yaml)
    }
    "json" => {
      print $"Configuration ($config_type): ($config_file)"
      print ""
      ($config | to json)
    }
    "toml" => {
      print $"Configuration ($config_type): ($config_file)"
      print ""
      ($config | to toml)
    }
    "nickel" => {
      # Show raw Nickel if available
      if ($config_file | str ends-with ".ncl") {
        open $config_file
      } else {
        print "ℹ️  Configuration is stored in YAML format, not Nickel"
        print "   Use --format=yaml to view the config"
        ($config | to json)
      }
    }
    _ => ($config | to yaml)
  }
}

# Validate workspace configuration
export def "workspace-config-validate" [
  workspace_name?: string
] {
  let workspace = (get-workspace-context $workspace_name)

  print $"🔍 Validating workspace: ($workspace.name)"
  print ""

  mut all_valid = true

  # Check main config - try Nickel first, fallback to YAML
  let config_dir = ($workspace.path | path join "config")
  let decl_file = ($config_dir | path join "provisioning.ncl")
  let yaml_file = ($config_dir | path join "provisioning.yaml")

  # Try Nickel first, but fallback to YAML if compilation fails (silently)
  let config_file = if ($decl_file | path exists) {
    # Try Nickel compilation (silently - we have YAML fallback)
    let ncl_ok = (ncl-eval-soft $decl_file [] null | is-not-empty)
    if $ncl_ok {
      $decl_file
    } else if ($yaml_file | path exists) {
      # Silently fallback to YAML
      $yaml_file
    } else {
      $decl_file
    }
  } else if ($yaml_file | path exists) {
    $yaml_file
  } else {
    null
  }

  if ($config_file | is-empty) {
    print "✓ Main config: (not found)"
    print "  ❌ No Nickel (.ncl) or YAML (.yaml) config file found"
    $all_valid = false
  } else {
    let config_type = if ($config_file | str ends-with ".ncl") { "Nickel" } else { "YAML" }
    print $"✓ Main config: ($config_file) [($config_type)]"

    let config = if ($config_file | str ends-with ".ncl") {
      # Load Nickel config (silently, with fallback handled above)
      # Check if nickel.mod exists in the same directory - if so, use 'nickel export' from that directory
      let file_dir = ($config_file | path dirname)
      let file_name = ($config_file | path basename)
      let decl_mod_exists = (($file_dir | path join "nickel.mod") | path exists)

      let parsed = if $decl_mod_exists {
        # Package-based configs: must run from config dir so nickel.mod resolves correctly
        let res = (do { ^sh -c $"cd '($file_dir)' && nickel export ($file_name) --format json" } | complete)
        if ($res.stdout | is-not-empty) { $res.stdout | from json } else { null }
      } else {
        ncl-eval-soft $config_file [] null
      }

      if ($parsed | is-empty) {
        print $"  ❌ Nickel compilation failed, but YAML fallback not available"
        $all_valid = false
        {}
      } else {
        if (($parsed | columns) | any { |col| $col == "workspace_config" }) {
          $parsed.workspace_config
        } else {
          $parsed
        }
      }
    } else {
      # Load YAML config - open handles parsing automatically
      open $config_file
    }

    if ($config | is-not-empty) {
      if ($config_file | str ends-with ".ncl") {
        print "  ✅ Valid Nickel (schema validated)"
      } else {
        print "  ✅ Valid YAML"
      }

      # Validate required sections
      if ($config | get workspace? | default null | is-empty) {
        print $"  ⚠️  Missing 'workspace' section"
      }
      if ($config | get paths? | default null | is-empty) {
        print $"  ⚠️  Missing 'paths' section"
      }
    }
  }

  # Check providers
  print ""
  print "Providers:"
  let providers_dir = ($workspace.path | path join "config" | path join "providers")
  if ($providers_dir | path exists) {
    let provider_files = (glob $"($providers_dir)/*.toml")
    if ($provider_files | is-empty) {
      print "  ⚠️  No provider configs found"
    } else {
      for file in $provider_files {
        let provider_name = ($file | path basename | str replace ".toml" "")
        print $"  ✓ ($provider_name): ($file)"

        # Validate TOML
        let _ = (open $file)
        print $"    ✅ Valid TOML"
      }
    }
  } else {
    print "  ⚠️  No providers directory"
  }

  # Check platform services
  print ""
  print "Platform Services:"
  let platform_dir = ($workspace.path | path join "config" | path join "platform")
  if ($platform_dir | path exists) {
    let platform_files = (glob $"($platform_dir)/*.toml")
    if ($platform_files | is-empty) {
      print "  ⚠️  No platform service configs found"
    } else {
      for file in $platform_files {
        let service_name = ($file | path basename | str replace ".toml" "")
        print $"  ✓ ($service_name): ($file)"

        let _ = (open $file)
        print $"    ✅ Valid TOML"
      }
    }
  } else {
    print "  ⚠️  No platform services directory"
  }

  # Check KMS
  print ""
  print "KMS Configuration:"
  let kms_file = ($workspace.path | path join "config" | path join "kms.toml")
  if ($kms_file | path exists) {
    print $"  ✓ KMS config: ($kms_file)"
    let _ = (open $kms_file)
    print $"    ✅ Valid TOML"
  } else {
    print "  ⚠️  KMS not configured"
  }

  print ""
  if $all_valid {
    print "✅ Validation complete - all configs are valid"
  } else {
    print "❌ Validation failed - some configs have errors"
  }

  $all_valid
}

# Generate provider config for workspace
export def "workspace-config-generate-provider" [
  provider_name: string
  workspace_name?: string
] {
  let workspace = (get-workspace-context $workspace_name)

  # Find provider template
  let provisioning_path = $env.PROVISIONING_PATH?
  if ($provisioning_path | is-empty) {
    print "❌ PROVISIONING_PATH environment variable not set"
    exit 1
  }

  let template_dir = ($provisioning_path | path join "extensions" | path join "providers" | path join $provider_name)
  let template_file = ($template_dir | path join "config.defaults.toml")

  if not ($template_file | path exists) {
    print "❌ Provider template not found: ($provider_name)"
    exit 1
  }

  # Generate config
  let output_dir = ($workspace.path | path join "config" | path join "providers")
  mkdir $output_dir

  let output_file = ($output_dir | path join $"($provider_name).toml")

  # Copy and interpolate template
  let template = (open $template_file)
  let content = (
    $template
    | str replace --all "{{workspace.path}}" $workspace.path
    | str replace --all "{{workspace.name}}" $workspace.name
  )

  $content | save $output_file

  print $"✅ Provider config generated: ($output_file)"
  print $"💡 Edit the file to customize settings"
}

# Edit configuration file
export def "workspace-config-edit" [
  config_type: string  # provider, platform, kms, main
  name?: string        # provider/platform name (not needed for kms/main)
  workspace_name?: string
] {
  let workspace = (get-workspace-context $workspace_name)

  let config_file = match $config_type {
    "main" => ($workspace.path | path join "config" | path join "provisioning.yaml")
    "provider" => {
      if ($name | is-empty) {
        print "❌ Provider name required"
        exit 1
      }
      ($workspace.path | path join "config" | path join "providers" | path join $"($name).toml")
    }
    "platform" => {
      if ($name | is-empty) {
        print "❌ Platform service name required"
        exit 1
      }
      ($workspace.path | path join "config" | path join "platform" | path join $"($name).toml")
    }
    "kms" => ($workspace.path | path join "config" | path join "kms.toml")
    _ => {
      print "❌ Unknown config type: ($config_type)"
      exit 1
    }
  }

  if not ($config_file | path exists) {
    print "❌ Config file not found: ($config_file)"
    exit 1
  }

  let editor = ($env.EDITOR? | default "vi")
  ^$editor $config_file
}

# Show configuration hierarchy
export def "workspace-config-hierarchy" [
  workspace_name?: string
] {
  let workspace = (get-workspace-context $workspace_name)

  print $"📊 Configuration Hierarchy for: ($workspace.name)"
  print "=================================================="
  print ""
  print "Priority (highest to lowest):"
  print ""

  print "5. Environment Variables (highest)"
  print "   PROVISIONING_*"
  print ""

  print "4. User Context"
  let user_config = ([$env.HOME "Library" "Application Support" "provisioning" $"ws_($workspace.name).yaml"] | path join)
  print $"   ($user_config)"
  if ($user_config | path exists) {
    print "   ✅ Exists"
  } else {
    print "   ⚠️  Not found"
  }
  print ""

  print "3. Platform Services"
  let platform_dir = ($workspace.path | path join "config" | path join "platform")
  print $"   ($platform_dir)/"
  if ($platform_dir | path exists) {
    let files = (ls $"($platform_dir)/*.toml" | get name)
    if ($files | is-empty) {
      print "   ⚠️  No platform configs"
    } else {
      for file in $files {
        print $"   • ($file | path basename)"
      }
    }
  } else {
    print "   ⚠️  No platform configs"
  }
  print ""

  print "2. Provider Configs"
  let providers_dir = ($workspace.path | path join "config" | path join "providers")
  print $"   ($providers_dir)/"
  if ($providers_dir | path exists) {
    let files = (ls $"($providers_dir)/*.toml" | get name)
    if ($files | is-empty) {
      print "   ⚠️  No provider configs"
    } else {
      for file in $files {
        print $"   • ($file | path basename)"
      }
    }
  } else {
    print "   ⚠️  No provider configs"
  }
  print ""

  print "1. Workspace Config (lowest)"
  let main_config = ($workspace.path | path join "config" | path join "provisioning.yaml")
  print $"   ($main_config)"
  if ($main_config | path exists) {
    print "   ✅ Exists"
  } else {
    print "   ❌ Not found"
  }
}

# List all configuration files for workspace
export def "workspace-config-list" [
  workspace_name?: string
  --type: string = "all"  # all, provider, platform, kms, main
] {
  let workspace = (get-workspace-context $workspace_name)

  print $"📋 Configuration Files for: ($workspace.name)"
  print "=================================================="
  print ""

  mut configs = []

  # Main config
  if ($type == "all" or $type == "main") {
    let main_config = ($workspace.path | path join "config" | path join "provisioning.yaml")
    if ($main_config | path exists) {
      $configs = ($configs | append {
        type: "main"
        name: "provisioning.yaml"
        path: $main_config
        exists: true
      })
    }
  }

  # Provider configs
  if ($type == "all" or $type == "provider") {
    let providers_dir = ($workspace.path | path join "config" | path join "providers")
    if ($providers_dir | path exists) {
      let provider_files = (ls $"($providers_dir)/*.toml" | get name)
      for file in $provider_files {
        $configs = ($configs | append {
          type: "provider"
          name: ($file | path basename | str replace ".toml" "")
          path: $file
          exists: true
        })
      }
    }
  }

  # Platform configs
  if ($type == "all" or $type == "platform") {
    let platform_dir = ($workspace.path | path join "config" | path join "platform")
    if ($platform_dir | path exists) {
      let platform_files = (ls $"($platform_dir)/*.toml" | get name)
      for file in $platform_files {
        $configs = ($configs | append {
          type: "platform"
          name: ($file | path basename | str replace ".toml" "")
          path: $file
          exists: true
        })
      }
    }
  }

  # KMS config
  if ($type == "all" or $type == "kms") {
    let kms_file = ($workspace.path | path join "config" | path join "kms.toml")
    if ($kms_file | path exists) {
      $configs = ($configs | append {
        type: "kms"
        name: "kms"
        path: $kms_file
        exists: true
      })
    }
  }

  $configs | table
}
