# Workspace Configuration Migration: YAML → Nickel
# Converts existing provisioning.yaml workspace configs to Nickel format
# Error handling: do/complete pattern with exit_code checks (no try-catch)

use ../config/accessor.nu *
use ../utils/nickel_processor.nu [ncl-eval]

# ============================================================================
# Convert YAML Workspace Config to Nickel
# ============================================================================

export def migrate-config [
  workspace_name?: string       # Optional: specific workspace to migrate
  --all                        # Migrate all workspaces
  --backup                     # Create backups of original YAML files
  --check                      # Check mode (show what would be done)
  --force                      # Force migration even if Nickel file exists
  --verbose                    # Verbose output
] {
  # Validate inputs
  if ($all and ($workspace_name | is-not-empty)) {
    print "❌ Cannot specify both --all and a workspace name"
    exit 1
  }

  if (not $all and ($workspace_name | is-empty)) {
    print "❌ Please specify either a workspace name or use --all flag"
    exit 1
  }

  # Get list of workspaces to migrate
  let workspaces_to_migrate = if $all {
    # Migrate all registered workspaces
    let registered = (list-workspaces)
    if ($registered | length) == 0 {
      print "ℹ️  No registered workspaces found"
      return
    }
    $registered
  } else {
    # Migrate specific workspace
    let contexts = (list-workspaces)
    let found = ($contexts | where name == $workspace_name | first)

    if ($found | is-empty) {
      print $"❌ Workspace '($workspace_name)' not found"
      exit 1
    }

    [$found]
  }

  # Migrate each workspace
  let results = ($workspaces_to_migrate | map {|ws|
    migrate_single_workspace $ws.path $ws.name --backup=$backup --check=$check --force=$force --verbose=$verbose
  })

  # Print summary
  print ""
  print "Migration Summary"
  print "=" | str repeat 50

  let successful = ($results | where success == true | length)
  let failed = ($results | where success == false | length)
  let skipped = ($results | where skipped == true | length)

  print $"✅ Successful: ($successful)"
  print $"⚠️  Skipped: ($skipped)"
  print $"❌ Failed: ($failed)"

  if $failed > 0 {
    print ""
    print "Failed migrations:"
    $results | where success == false | each {|r|
      print $"  - ($r.workspace): ($r.error)"
    }
  }
}

# ============================================================================
# Migrate Single Workspace
# ============================================================================

def migrate_single_workspace [
  workspace_path: string
  workspace_name: string
  --backup: bool
  --check: bool
  --force: bool
  --verbose: bool
] {
  let yaml_file = ($workspace_path | path join "config" | path join "provisioning.yaml")
  let decl_file = ($workspace_path | path join "config" | path join "provisioning.ncl")

  if $verbose {
    print $"Processing workspace: ($workspace_name)"
    print $"  YAML: ($yaml_file)"
    print $"  Nickel:  ($decl_file)"
  }

  # Check if YAML config exists
  if not ($yaml_file | path exists) {
    if $verbose {
      print $"  ⚠️  No YAML config found, skipping"
    }
    return {
      workspace: $workspace_name
      success: false
      skipped: true
      error: "YAML config not found"
    }
  }

  # Check if Nickel file already exists
  if ($decl_file | path exists) and (not $force) {
    if $verbose {
      print $"  ⚠️  Nickel file already exists, skipping (use --force to overwrite)"
    }
    return {
      workspace: $workspace_name
      success: false
      skipped: true
      error: "Nickel file already exists"
    }
  }

  # Load YAML config
  let yaml_load_result = (do { open $yaml_file } | complete)
  if $yaml_load_result.exit_code != 0 {
    if $verbose {
      print $"  ❌ Failed to parse YAML"
    }
    return {
      workspace: $workspace_name
      success: false
      skipped: false
      error: "Failed to parse YAML"
    }
  }
  let yaml_config = $yaml_load_result.stdout

  # Convert YAML to Nickel
  let nickel_content = (yaml_to_nickel $yaml_config $workspace_name)

  if $check {
    if $verbose {
      print $"  [CHECK MODE] Would write ($decl_file | str length) characters"
      print ""
      print "Generated Nickel (first 500 chars):"
      print ($nickel_content | str substring [0 500])
      print "..."
    }
    return {
      workspace: $workspace_name
      success: true
      skipped: false
      error: null
    }
  }

  # Create backup if requested
  if $backup and ($yaml_file | path exists) {
    let backup_file = $"($yaml_file).backup"
    let backup_result = (do { cp $yaml_file $backup_file } | complete)
    if $backup_result.exit_code == 0 {
      if $verbose {
        print $"  📦 Backed up to ($backup_file)"
      }
    } else if $verbose {
      print $"  ⚠️  Failed to create backup"
    }
  }

  # Write Nickel file
  let save_result = (do { $nickel_content | save $decl_file } | complete)
  if $save_result.exit_code != 0 {
    if $verbose {
      print $"  ❌ Failed to write Nickel file: ($save_result.stderr)"
    }
    return {
      workspace: $workspace_name
      success: false
      skipped: false
      error: $"Failed to write Nickel file: ($save_result.stderr)"
    }
  }

  if $verbose {
    print $"  ✅ Created ($decl_file)"
  }

  # Validate Nickel
  let validate_result = (try {
    ncl-eval $decl_file []
    true
  } catch {
    false
  })
  if $validate_result {
    if $verbose {
      print $"  ✅ Nickel validation passed"
    }
  } else if $verbose {
    print $"  ⚠️  Nickel validation warning (may still be usable)"
  }

  return {
    workspace: $workspace_name
    success: true
    skipped: false
    error: null
  }
}

# ============================================================================
# YAML to Nickel Conversion
# ============================================================================

def yaml_to_nickel [
  yaml_config: record
  workspace_name: string
] {
  # Start building Nickel structure
  let nickel_lines = [
    '"""'
    'Workspace Configuration'
    'Auto-generated from provisioning.yaml'
    '"""'
    ''
    'import provisioning.workspace_config as ws'
    ''
    'workspace_config = ws.WorkspaceConfig {'
  ]

  # Add workspace section
  let workspace_section = if ($yaml_config | get -o workspace? | default null | is-not-empty) {
    let ws = ($yaml_config | get workspace)
    @[
      '    workspace: {'
      $'        name: "($ws.name | default $workspace_name)"'
      $'        version: "($ws.version | default "1.0.0")"'
      if ($ws.created? | is-not-empty) {
        $'        created: "($ws.created)"'
      } else {
        '        created: "2025-12-03T00:00:00Z"'
      }
      '    }'
    ] | str join "\n"
  } else {
    @[
      '    workspace: {'
      $'        name: "($workspace_name)"'
      '        version: "1.0.0"'
      '        created: "2025-12-03T00:00:00Z"'
      '    }'
    ] | str join "\n"
  }

  # Add paths section
  let paths_section = if ($yaml_config | get -o paths? | default null | is-not-empty) {
    let paths = ($yaml_config | get paths)
    let path_entries = [
      (if ($paths.base? | is-not-empty) { $'        base: "($paths.base)"' } else { null })
      (if ($paths.infra? | is-not-empty) { $'        infra: "($paths.infra)"' } else { null })
      (if ($paths.cache? | is-not-empty) { $'        cache: "($paths.cache)"' } else { null })
      (if ($paths.runtime? | is-not-empty) { $'        runtime: "($paths.runtime)"' } else { null })
    ] | compact

    @[
      '    paths: {'
      ...($path_entries)
      '    }'
    ] | str join "\n"
  } else {
    @[
      '    paths: {'
      '        base: ""'
      '    }'
    ] | str join "\n"
  }

  # Add provisioning section
  let provisioning_section = if ($yaml_config | get -o provisioning? | default null | is-not-empty) {
    let prov = ($yaml_config | get provisioning)
    @[
      '    provisioning: {'
      $'        path: "($prov.path | default "")"'
      '    }'
    ] | str join "\n"
  } else {
    @[
      '    provisioning: {'
      '        path: ""'
      '    }'
    ] | str join "\n"
  }

  # Add core section
  let core_section = if ($yaml_config | get -o core? | default null | is-not-empty) {
    let core = ($yaml_config | get core)
    @[
      '    core: {'
      $'        version: "($core.version | default "1.0.0")"'
      $'        name: "($core.name | default "provisioning")"'
      '    }'
    ] | str join "\n"
  } else {
    @[
      '    core: {'
      '        version: "1.0.0"'
      '        name: "provisioning"'
      '    }'
    ] | str join "\n"
  }

  # Add remaining sections (simplified - keeping existing values or defaults)
  let debug_section = '    debug: {}'
  let output_section = '    output: {}'
  let http_section = '    http: {}'
  let providers_section = '    providers: {}'
  let platform_section = '    platform: {}'
  let secrets_section = '    secrets: {}'
  let kms_section = '    kms: { config_file: "" }'
  let sops_section = '    sops: { config_path: "" }'
  let ai_section = '    ai: {}'
  let taskservs_section = '    taskservs: { run_path: "" }'
  let clusters_section = '    clusters: { run_path: "" }'
  let generation_section = '    generation: { dir_path: "" }'
  let cache_section = '    cache: { path: "" }'
  let infra_section = '    infra: {}'
  let tools_section = '    tools: {}'
  let nickel_section = '    nickel: {}'
  let ssh_section = '    ssh: {}'

  # Assemble final Nickel
  let nickel_content = ([
    ...$nickel_lines
    ''
    $workspace_section
    ''
    $paths_section
    ''
    $provisioning_section
    ''
    $core_section
    ''
    $debug_section
    ''
    $output_section
    ''
    $http_section
    ''
    $providers_section
    ''
    $platform_section
    ''
    $secrets_section
    ''
    $kms_section
    ''
    $sops_section
    ''
    $ai_section
    ''
    $taskservs_section
    ''
    $clusters_section
    ''
    $generation_section
    ''
    $cache_section
    ''
    $infra_section
    ''
    $tools_section
    ''
    $nickel_section
    ''
    $ssh_section
    '}'
  ] | str join "\n")

  $nickel_content
}
