# Workspace sync and update operations
# Synchronizes workspace hidden directories with provisioning source

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

# Update all workspace hidden directories and content
export def "workspace update" [
  workspace_name?: string  # Workspace name/path (default: active workspace)
  --check (-c)             # Check mode - show what would be updated
  --force (-f)             # Force update without confirmation
  --yes (-y)               # Alias for --force (skip confirmation)
  --verbose (-v)           # Verbose output
] {
  # --yes is an alias for --force
  let force_final = ($force or $yes)

  # Get workspace to update
  let ws_name = if ($workspace_name | is-not-empty) {
    $workspace_name
  } else {
    let active = (get-active-workspace)
    if ($active == null or ($active | is-empty)) {
      print $"(ansi red)✗(ansi reset) No active workspace"
      print $"(ansi yellow)Specify workspace name or activate a workspace first(ansi reset)"
      exit 1
    }
    $active
  }

  let workspace_path = (get-workspace-path $ws_name)

  if ($workspace_path == null or not ($workspace_path | path exists)) {
    print $"(ansi red)✗(ansi reset) Workspace not found: ($ws_name)"
    exit 1
  }

  # Find provisioning root (parent of workspace - might be 1 or 2 levels up)
  let parent1 = ($workspace_path | path dirname)
  let parent2 = ($parent1 | path dirname)

  let prov_root = if (($parent1 | path join "provisioning" | path exists)) {
    $parent1
  } else if (($parent2 | path join "provisioning" | path exists)) {
    $parent2
  } else {
    ""
  }

  if ($prov_root | is-empty) {
    print $"(ansi red)✗(ansi reset) Cannot find provisioning root"
    print "  Expected: <root>/provisioning"
    print $"  Workspace: ($workspace_path)"
    exit 1
  }

  print $"(ansi cyan)🔄 Updating workspace...(ansi reset)"
  print $"  Workspace: (ansi green)($ws_name)(ansi reset)"
  print $"  Path: ($workspace_path)"
  print ""

  # Define what to update
  let updates = [
    {name: ".providers", source: ($prov_root | path join "provisioning/extensions/providers"), target: ($workspace_path | path join ".providers")}
    {name: ".clusters", source: ($prov_root | path join "provisioning/extensions/clusters"), target: ($workspace_path | path join ".clusters")}
    {name: ".taskservs", source: ($prov_root | path join "provisioning/extensions/taskservs"), target: ($workspace_path | path join ".taskservs")}
    {name: ".nickel", source: ($prov_root | path join "provisioning/nickel"), target: ($workspace_path | path join ".nickel")}
  ]

  # Show plan
  print $"(ansi green_bold)Directories to update:(ansi reset)"
  print ""

  for update in $updates {
    let src_exists = ($update.source | path exists)
    let status = if $src_exists { $"(ansi green)✓(ansi reset)" } else { $"(ansi yellow)⊘(ansi reset)" }
    print $"  ($status) ($update.name)"
    if $verbose {
      print $"      Source: ($update.source)"
      print $"      Target: ($update.target)"
    }
  }

  print ""

  # Check mode
  if $check {
    print $"(ansi cyan)[CHECK MODE](ansi reset) No changes will be made"
    return
  }

  # Confirmation - require --yes flag
  if not $force_final {
    print $"(ansi yellow)⚠ This will overwrite existing directories(ansi reset)"
    print ""
    print "To proceed, use: provisioning ws update --yes"
    return
  }

  print ""
  print $"(ansi cyan)Updating...(ansi reset)"
  print ""

  # Perform updates
  for update in $updates {
    let src_exists = ($update.source | path exists)

    if not $src_exists {
      print $"  (ansi yellow)⊘(ansi reset) Skipped: ($update.name) \(source-not-found\)"
      continue
    }

    # Remove existing target
    if ($update.target | path exists) {
      rm -rf $update.target
      if $verbose {
        print $"  Removed: ($update.name)"
      }
    }

    # Copy from source
    cp -r $update.source $update.target
    print $"  (ansi green)✓(ansi reset) Updated: ($update.name)"

    # Fix Nickel module paths after copy (for providers)
    if ($update.name == ".providers") {
      _fix-provider-nickel-paths $update.target $verbose
    }
  }

  print ""
  print $"(ansi green)✓(ansi reset) Workspace update complete"
}

# Helper: Fix nickel.mod paths in copied providers
def _fix-provider-nickel-paths [
  providers_path: string
  verbose: bool
] {
  # Find all nickel.mod files in provider subdirectories
  let nickel_mods = (glob $"($providers_path)/**/nickel.mod")

  if ($nickel_mods | is-empty) {
    return
  }

  for mod_file in $nickel_mods {
    if not ($mod_file | path exists) {
      continue
    }

    # Read the file
    let content = (open $mod_file)

    # Fix provider paths to correct relative paths
    # Providers are in infra/<name>/.providers/<provider>/nickel/nickel.mod
    # Should reference: ../../../.nickel/packages/provisioning
    let updated = (
      $content
      | str replace --all '{ path = "../../../../nickel' '{ path = "../../../.nickel/packages/provisioning'
      | str replace --all '{ path = "../../../../.nickel' '{ path = "../../../.nickel/packages/provisioning'
    )

    # Only write if content changed
    if ($content != $updated) {
      $updated | save -f $mod_file
      if $verbose {
        print $"      Fixed Nickel path in: ($mod_file)"
      }
    }
  }
}

# Check workspace update status
export def "workspace check-updates" [
  workspace_name?: string  # Workspace name/path (default: active workspace)
  --verbose (-v)           # Verbose output
] {
  # Get workspace to check
  let ws_name = if ($workspace_name | is-not-empty) {
    $workspace_name
  } else {
    let active = (get-active-workspace)
    if ($active == null or ($active | is-empty)) {
      print $"(ansi red)✗(ansi reset) No active workspace"
      print $"(ansi yellow)Specify workspace name or activate a workspace first(ansi reset)"
      exit 1
    }
    $active
  }

  let workspace_path = (get-workspace-path $ws_name)

  if ($workspace_path == null or not ($workspace_path | path exists)) {
    print $"(ansi red)✗(ansi reset) Workspace not found: ($ws_name)"
    exit 1
  }

  print $"(ansi cyan)📋 Checking workspace updates...(ansi reset)"
  print $"  Workspace: (ansi green)($ws_name)(ansi reset)"
  print $"  Path: ($workspace_path)"
  print ""

  let checks = [
    {name: ".providers", path: ($workspace_path | path join ".providers")}
    {name: ".clusters", path: ($workspace_path | path join ".clusters")}
    {name: ".taskservs", path: ($workspace_path | path join ".taskservs")}
    {name: ".nickel", path: ($workspace_path | path join ".nickel")}
    {name: "config", path: ($workspace_path | path join "config")}
  ]

  let status_list = ($checks | each { |check|
    let exists = ($check.path | path exists)
    if $exists {
      print $"  (ansi green)✓(ansi reset) ($check.name) - present"
    } else {
      print $"  (ansi yellow)⊘(ansi reset) ($check.name) - missing"
    }
    if $verbose {
      print $"      Path: ($check.path)"
    }
    {name: $check.name, exists: $exists}
  })

  let missing_count = ($status_list | where {|s| $s.exists == false} | length)

  print ""

  if $missing_count == 0 {
    print $"(ansi green)✓(ansi reset) All directories are present and up-to-date"
  } else {
    let label = if $missing_count == 1 { "directory needs" } else { "directories need" }
    print $"(ansi yellow)⚠(ansi reset) ($missing_count) ($label) updating"
    print ""
    print $"(ansi cyan)Update with:(ansi reset) provisioning workspace update"
  }
}

# Sync workspace-specific subdirectories
export def "workspace sync-modules" [
  workspace_name?: string  # Workspace name/path (default: active workspace)
  --check (-c)             # Check mode
  --force (-f)             # Force sync
  --verbose (-v)           # Verbose output
] {
  # Get workspace to sync
  let ws_name = if ($workspace_name | is-not-empty) {
    $workspace_name
  } else {
    let active = (get-active-workspace)
    if ($active == null or ($active | is-empty)) {
      print $"(ansi red)✗(ansi reset) No active workspace"
      print $"(ansi yellow)Specify workspace name or activate a workspace first(ansi reset)"
      exit 1
    }
    $active
  }

  let workspace_path = (get-workspace-path $ws_name)

  if ($workspace_path == null or not ($workspace_path | path exists)) {
    print $"(ansi red)✗(ansi reset) Workspace not found: ($ws_name)"
    exit 1
  }

  let config_path = ($workspace_path | path join "config")

  if not ($config_path | path exists) {
    print $"(ansi red)✗(ansi reset) Workspace config not found"
    exit 1
  }

  print $"(ansi cyan)🔄 Syncing workspace modules...(ansi reset)"
  print $"  Workspace: (ansi green)($ws_name)(ansi reset)"
  print $"  Path: ($workspace_path)"
  print ""

  # List providers from config
  if (($config_path | path join "providers") | path exists) {
    print "Configured Providers:"
    ls ($config_path | path join "providers")
    | where { |f| ($f.type == "file") and ($f.name | str ends-with ".toml") }
    | each { |f|
      print $"  - ($f.name)"
    } | ignore
  }

  # List clusters from config
  if (($config_path | path join "clusters") | path exists) {
    print ""
    print "Configured Clusters:"
    ls ($config_path | path join "clusters")
    | where { |f| ($f.type == "file") and ($f.name | str ends-with ".toml") }
    | each { |f|
      print $"  - ($f.name)"
    } | ignore
  }

  print ""
  print $"(ansi green)✓(ansi reset) Module sync complete"
}
