#!/usr/bin/env nu
# Info: Script to run Provisioning Template Management
# Author: JesusPerezLorenzo
# Release: 1.0.0
# Date: 29-09-2025

use std log

use lib_provisioning *
use env.nu *

# - > Help on Template
export def "main help" [
  --src: string = ""
  --notitles       # not titles
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if $notitles == null or not $notitles { show_titles }
  ^$"($env.PROVISIONING_NAME)" -mod template --help
  if ($out | is-not-empty) { $env.PROVISIONING_NO_TERMINAL = false }
  print (provisioning_options $src)
  if not $env.PROVISIONING_DEBUG { end_run "" }
}

# > Template Management
def main [
  ...args: string  # Other options, use help to get info
  -v               # Show version
  -i               # Show Info
  --version (-V)   # Show version with title
  --info (-I)      # Show Info with title
  --about (-a)     # Show About
  --infra: string  # Infrastructure name
  --provider: string = ""  # Provider name
  --type: string = ""      # Template type: taskservs, providers, servers, clusters
  --layer: string = "workspace"  # Layer: core, workspace, infra
  --dry-run        # Show what would be done without doing it
  --backup         # Create backup before operations
  --force (-f)     # Force operation
  --check (-c)     # Only check mode, no actual changes
  --yes (-y)       # Confirm task
  --debug (-x)     # Use Debug mode
  --xm             # Debug with PROVISIONING_METADATA
  --xld            # Log level with DEBUG PROVISIONING_LOG_LEVEL=debug
  --metadata       # Error with metadata (-xm)
  --notitles       # Do not show banner titles
  --helpinfo (-h)  # For more details use options "help" (no dashes)
  --out: string    # Print Output format: json, yaml, text (default)
]: nothing -> nothing {
  if ($out | is-not-empty) {
    $env.PROVISIONING_OUT = $out
    $env.PROVISIONING_NO_TERMINAL = true
  }
  provisioning_init $helpinfo "template" $args
  if $version or $v { ^$env.PROVISIONING_NAME -v ; exit }
  if $info or $i { ^$env.PROVISIONING_NAME -i ; exit }
  if $about {
    _print (get_about_info)
    exit
  }
  if $debug { $env.PROVISIONING_DEBUG = true }
  if $metadata { $env.PROVISIONING_METADATA = true }

  let task = if ($args | length) > 0 { ($args | get 0) } else { "" }
  let ops = if ($args | length) > 1 { ($args | skip 1 | str join " ") } else { "" }
  let template_name = if ($ops | is-not-empty) and not ($ops | str starts-with "-") {
    ($ops | split row " " | get 0)
  } else {
    ""
  }
  let target_infra = if ($ops | split row " " | length) > 1 {
    ($ops | split row " " | get 1)
  } else {
    $infra
  }

  $env.PROVISIONING_MODULE = "template"

  match $task {
    "h" | "help" => {
      # Redirect to main categorized help system
      exec $"($env.PROVISIONING_NAME)" help workspace --notitles
    },
    "list" | "ls" => {
      template_list --type $type --out $out
    },
    "types" => {
      template_types --out $out
    },
    "show" => {
      if ($template_name | is-empty) {
        print "❌ Template name required"
        print "Usage: provisioning template show <name>"
        exit 1
      }
      template_show $template_name --type $type --out $out
    },
    "apply" => {
      if ($template_name | is-empty) or ($target_infra | is-empty) {
        print "❌ Template name and target infrastructure required"
        print "Usage: provisioning template apply <template_name> <infra_name> --provider <provider>"
        exit 1
      }
      if $dry_run {
        template_apply $template_name $target_infra --provider $provider --dry-run
      } else {
        template_apply $template_name $target_infra --provider $provider
      }
    },
    "extract" => {
      if ($target_infra | is-empty) {
        print "❌ Infrastructure name required"
        print "Usage: provisioning template extract <infra_name>"
        exit 1
      }
      if $dry_run {
        template_extract $target_infra --type $type --dry-run
      } else {
        template_extract $target_infra --type $type
      }
    },
    "convert" => {
      if ($target_infra | is-empty) {
        print "❌ Infrastructure name required"
        print "Usage: provisioning template convert <infra_name>"
        exit 1
      }
      if $backup and $dry_run {
        template_convert $target_infra --backup --dry-run
      } else if $backup {
        template_convert $target_infra --backup
      } else if $dry_run {
        template_convert $target_infra --dry-run
      } else {
        template_convert $target_infra
      }
    },
    "validate" => {
      if ($target_infra | is-empty) {
        print "❌ Infrastructure name required"
        print "Usage: provisioning template validate <infra_name>"
        exit 1
      }
      template_validate $target_infra
    },
    "layer" => {
      template_layer_info --infra $target_infra --out $out
    },
    _ => {
      print $"❌ Unknown task: ($task)"
      print "Use 'provisioning template help' for available commands"
      exit 1
    }
  }
}

# List available templates
def template_list [
  --type: string
  --out: string
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let templates_path = ($provisioning_root | path join "workspace" "templates")

  if not ($templates_path | path exists) {
    print "❌ Templates directory not found"
    exit 1
  }

  let template_types = if ($type | is-not-empty) {
    [$type]
  } else {
    ["taskservs", "providers", "servers", "clusters"]
  }

  let all_templates = ($template_types | each {|ttype|
    let type_path = ($templates_path | path join $ttype)
    if ($type_path | path exists) {
      let items = (ls $type_path | where type == dir | select name)
      $items | each {|item| {
        type: $ttype
        name: ($item.name | path basename)
        path: $item.name
      }}
    } else {
      []
    }
  } | flatten)

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($all_templates | to json)
    } else if $out == "yaml" {
      print ($all_templates | to yaml)
    } else {
      print ($all_templates | table)
    }
  } else {
    print "📋 Available Templates:"
    for template in $all_templates {
      print $"  [($template.type)] ($template.name)"
    }
  }
}

# List template types
def template_types [--out: string]: nothing -> nothing {
  let types = [
    {type: "taskservs", description: "Task service configurations (kubernetes, containerd, etc.)"}
    {type: "providers", description: "Cloud provider templates (upcloud, aws, local)"}
    {type: "servers", description: "Server configuration patterns"}
    {type: "clusters", description: "Complete cluster templates"}
  ]

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($types | to json)
    } else if $out == "yaml" {
      print ($types | to yaml)
    } else {
      print ($types | table)
    }
  } else {
    print "📁 Template Types:"
    for t in $types {
      print $"  ($t.type): ($t.description)"
    }
  }
}

# Show template details
def template_show [
  name: string
  --type: string
  --out: string
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let templates_path = ($provisioning_root | path join "workspace" "templates")

  let template_types = if ($type | is-not-empty) {
    [$type]
  } else {
    ["taskservs", "providers", "servers", "clusters"]
  }

  let found = ($template_types | each {|ttype|
    let template_path = ($templates_path | path join $ttype $name)
    if ($template_path | path exists) {
      let files = (ls $template_path | select name type size)
      {
        type: $ttype
        name: $name
        path: $template_path
        files: $files
      }
    } else {
      null
    }
  } | where {|x| $x != null} | first)

  if ($found | is-empty) {
    print $"❌ Template not found: ($name)"
    exit 1
  }

  if ($out | is-not-empty) {
    _print $found
  } else {
    print $"📦 Template: ($found.name)"
    print $"  Type: ($found.type)"
    print $"  Path: ($found.path)"
    print "  Files:"
    for file in $found.files {
      print $"    - ($file.name | path basename) [($file.type)] ($file.size)"
    }
  }
}

# Apply template to infrastructure
def template_apply [
  template_name: string
  target_infra: string
  --provider: string
  --dry-run
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let templates_path = ($provisioning_root | path join "workspace" "templates")

  # Find template
  let template_types = ["taskservs", "providers", "servers", "clusters"]
  let template_path = ($template_types | each {|ttype|
    let path = ($templates_path | path join $ttype $template_name)
    if ($path | path exists) {
      {type: $ttype, path: $path}
    } else {
      null
    }
  } | where {|x| $x != null} | first)

  if ($template_path | is-empty) {
    print $"❌ Template not found: ($template_name)"
    exit 1
  }

  let config = get-config
  let workspace_root = $config.paths.base? | default $env.PWD
  let target_path = ($workspace_root | path join "infra" $target_infra)

  if not ($target_path | path exists) {
    print $"❌ Infrastructure not found: ($target_infra)"
    exit 1
  }

  if $dry_run {
    print $"🔍 DRY RUN: Would apply template ($template_name) to ($target_infra)"
    print $"  Template type: ($template_path.type)"
    print $"  Template path: ($template_path.path)"
    print $"  Target path: ($target_path)"
    print $"  Provider: ($provider)"
  } else {
    print $"🔧 Applying template ($template_name) to ($target_infra)"

    let target_subdir = match $template_path.type {
      "taskservs" => "task-servs"
      "providers" => "defs"
      "servers" => "defs"
      "clusters" => "clusters"
      _ => $template_path.type
    }

    let dest_dir = ($target_path | path join $target_subdir)
    mkdir $dest_dir

    # Copy template files
    cp -r ($template_path.path | path join "*") $dest_dir

    print $"✅ Template applied: ($template_name) -> ($target_infra)"
    print $"📁 Files copied to: ($dest_dir)"
  }
}

# Extract patterns from infrastructure
def template_extract [
  infra_name: string
  --type: string
  --dry-run
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Migration script not found: ($migrate_script)"
    exit 1
  }

  let type_flag = if ($type | is-not-empty) { ["--type" $type] } else { [] }
  let dry_run_flag = if $dry_run { ["--dry-run"] } else { [] }

  ^nu $migrate_script extract $infra_name ...$type_flag ...$dry_run_flag
}

# Convert infrastructure to use templates
def template_convert [
  infra_name: string
  --backup
  --dry-run
]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Migration script not found: ($migrate_script)"
    exit 1
  }

  let backup_flag = if not $backup { ["--no-backup"] } else { [] }
  let dry_run_flag = if $dry_run { ["--dry-run"] } else { [] }

  ^nu $migrate_script convert $infra_name ...$backup_flag ...$dry_run_flag
}

# Validate template usage in infrastructure
def template_validate [infra_name: string]: nothing -> nothing {
  let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning"
  let migrate_script = ($provisioning_root | path join "workspace" "tools" "migrate-infra.nu")

  if not ($migrate_script | path exists) {
    print $"❌ Migration script not found: ($migrate_script)"
    exit 1
  }

  ^nu $migrate_script validate $infra_name
}

# Show layer information
def template_layer_info [
  --infra: string
  --out: string
]: nothing -> nothing {
  let layers = [
    {
      name: "core"
      priority: 100
      path: "provisioning/extensions/"
      description: "Base provisioning system extensions"
    }
    {
      name: "workspace"
      priority: 200
      path: "provisioning/workspace/templates/"
      description: "Shared templates and reusable configurations"
    }
    {
      name: "infrastructure"
      priority: 300
      path: $"workspace/infra/($infra | default '{name}')/"
      description: "Infrastructure-specific configurations and overrides"
    }
  ]

  if ($out | is-not-empty) {
    if $out == "json" {
      print ($layers | to json)
    } else if $out == "yaml" {
      print ($layers | to yaml)
    } else {
      print ($layers | table)
    }
  } else {
    print "🏗️  Layer Resolution Order:"
    print "   (Higher priority overrides lower priority)"
    print ""
    for layer in ($layers | reverse) {
      print $"  ($layer.priority) - ($layer.name | str upcase)"
      print $"      Path: ($layer.path)"
      print $"      ($layer.description)"
      print ""
    }
  }
}
