#!/usr/bin/env -S nu
# Author: JesusPerezLorenzo
# Release: 1.0.4
# Date: 6-2-2024

# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/config/accessor/functions.nu [
    get-provisioning-generate-dirpath get-provisioning-generate-defsfile
]

#use ../lib_provisioning/utils/templates.nu on_template_path

export def github_latest_tag [
  url: string = ""
  use_dev_release: bool = false
  id_target: string = "releases/tag"
] {
  #let res = (http get $url -r )
  if ($url | is-empty) { return "" }
  let res = (^curl -s $url | complete)
  let html_content = if ($res.exit_code != 0) {
      print $"🛑 Error (_ansi red)($url)(_ansi reset):\n ($res.exit_code) ($res.stderr)"
      return ""
  } else { $res.stdout }
  # curl -s https://github.com/project-zot/zot/tags | grep "<h2 " | grep "releases/tag"
  let versions = ($html_content | parse --regex '<h2 (?<a>.*?)</a>' | get a | each {|it|
    let parsed = ($it | parse --regex ($"($id_target)" + '/(?<version>.*?)"'))
    if ($parsed | is-empty) { "" } else { $parsed | get version | first }
  })
  let list = if $use_dev_release {
    $versions
  } else {
    ($versions | where {|it|
        not ($it | str contains "-rc") and not ($it | str contains "-alpha")
    })
  }
  if ($list | is-empty) { "" } else { $list | sort -r | first }
}

export def value_input_list [
  input_type: string
  options_list: list
  msg: string
  default_value: string
] {
  let selection_pos = ( $options_list
  | input list --index (
    $"(_ansi default_dimmed)Select(_ansi reset) (_ansi yellow_bold)($msg)(_ansi reset) " +
    $"\n(_ansi default_dimmed)\(use arrow keys and press [enter] or [escape] for default '(_ansi reset)" +
    $"($default_value)(_ansi default_dimmed)'\)(_ansi reset)"
  ))
  if $selection_pos != null {
    ($options_list | get $selection_pos)
  } else { $default_value }
}

export def value_input [
  input_type: string
  numchar: int
  msg: string
  default_value: string
  not_empty: bool
] {
  while true {
    let value_input = if $numchar > 0 {
      print ($"(_ansi yellow_bold)($msg)(_ansi reset) " +
        $"(_ansi default_dimmed) type value (_ansi green_bold)($numchar) chars(_ansi reset) " +
        $"(_ansi default_dimmed) default '(_ansi reset)" +
        $"($default_value)(_ansi default_dimmed)'(_ansi reset)"
      )
      (input --numchar $numchar)
    } else {
      print ($"(_ansi yellow_bold)($msg)(_ansi reset) " +
        $"(_ansi default_dimmed)\(type value and press [enter] default '(_ansi reset)" +
        $"($default_value)(_ansi default_dimmed)'\)(_ansi reset)"
      )
      (input)
    }
    if $not_empty and ($value_input | is-empty) {
      if ($default_value | is-not-empty) { return $default_value }
      continue
    } else if ($value_input | is-empty) {
      return $default_value
    }
    let result = match $input_type {
      "number" => {
        if ($value_input | parse --regex '^[0-9]' | length) > 0 { $value_input } else { "" }
      },
      "ipv4-address" => {
        if ($value_input | parse --regex '^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$' | length) > 0 { $value_input } else { "" }
      },
      _ => $value_input,
    }
    if $value_input != $result { continue }
    return $value_input
  }
  return $default_value
}

export def "generate_title" [
  title: string
] {
  _print $"\n(_ansi purple)((get-provisioning-name))(_ansi reset) (_ansi default_dimmed)generate:(_ansi reset) (_ansi cyan)($title)(_ansi reset)"
  _print $"(_ansi default_dimmed)-------------------------------------------------------------(_ansi reset)\n"
}

export def "generate_data_items" [
  defs_gen: list = []
  defs_values: list = []
] {
  mut data = {}
  for it in $defs_values {
    let input_type = ($it | get input_type? | default "")
    let options_list = ($it | get options_list? | default [])
    let numchar = ($it | get numchar? | default 0)
    let msg = ($it | get msg? | default "")
    let default_value = match $input_type {
      "list-record" | "list" => ($it | get default_value? | default []),
      "record" => ($it | get default_value? | default {}),
      _ => ($it | get default_value? | default ""),
    }
    let var = ($it | get var? | default "")
    let not_empty = ($it | get not_empty? | default false)
    print $input_type
    let value = match $input_type {
      "record" => (generate_data_items $it),
      "list-record" => {
        let record_key = ($it | get record? | default "")
        let record_value = if ($record_key | is-empty) or ($record_key not-in ($defs_gen | columns)) {
          []
        } else {
          $defs_gen | get $record_key
        }
        print ($record_value | table -e)
        #  where {|it| ($it | get -o  $record_key | is-not-empty)} | get -o 0 | get -o $record_key | default [])
        if ($record_value | is-empty) { continue }
        mut val = []
        while true {
          let selection_pos = ( [ $"Add ($msg)", $"No more ($var)" ]
          | input list --index (
            $"(_ansi default_dimmed)Select(_ansi reset) (_ansi yellow_bold)($msg)(_ansi reset) " +
            $"\n(_ansi default_dimmed)\(use arrow keys and press [enter] or [escape] to finish '(_ansi reset)"
          ))
          if $selection_pos == null or $selection_pos == 1 { break }
          $val = ($val | append (generate_data_items $defs_gen $record_value))
        }
        $val
      },
      "list" => (value_input_list $input_type $options_list $msg $default_value),
      _ => (value_input $input_type $numchar $msg $default_value $not_empty),
    }
    $data = ($data | merge { $var: $value })
  }
  $data
}

export def "generate_data_def" [
  root_path: string
  infra_name: string
  infra_path: string
  created: bool
  inputfile: string = ""
] {
  let data = (if ($inputfile | is-empty) {
    let defs_path = ($root_path | path join (get-provisioning-generate-dirpath) | path join (get-provisioning-generate-defsfile))
    if ( $defs_path | path exists) {
      let data_gen = (open $defs_path)
      let title = $"($data_gen| get title? | default "")"
      generate_title $title
      let defs_values = ($data_gen | get defs_values? | default [])
      (generate_data_items $data_gen $defs_values)
    } else {
      if (is-debug-enabled) { _print  $"🛑 ((get-provisioning-name)) generate: Invalid path (_ansi red)($defs_path)(_ansi reset)" }
    }
  } else {
    (open $inputfile)
  } | merge {
    infra_name: $infra_name,
    infra_path: $infra_path,
  })
  let vars_filepath = $"/tmp/data_($infra_name)_($env.NOW).yaml"
  ($data | to yaml | str replace "$name" $infra_name| save -f $vars_filepath)
  let remove_files = if (is-debug-enabled) { false } else { true }
  on_template_path $infra_path $vars_filepath $remove_files true
  if not (is-debug-enabled) {
    rm -f $vars_filepath
  }
}
