
use ../utils/on_select.nu run_on_selection
export def get_provisioning_info [
    dir_path: string
    target: string 
]: nothing -> list {
    # task root path target will be empty 
    let item =  if $target != "" { $target } else { ($dir_path | path basename) }
    let full_path = if $target != "" { $"($dir_path)/($item)" } else { $dir_path }
    if not ($full_path | path exists) { 
        _print $"🛑 path found for (_ansi cyan)($full_path)(_ansi reset)" 
        return []
    }
    ls -s  $full_path | where {|el|(
            $el.type == "dir" 
            # discard paths with "_" prefix 
            and ($el.name != "generate" )
            and ($el.name | str starts-with "_") == false 
            and (
                # for main task directory at least has default
                ($full_path | path join $el.name | path join "default" | path exists)  
                # for modes in  task directory at least has install-task.sh file 
                or ($"($full_path)/($el.name)/install-($item).sh" | path exists) 
            )
        )} |
        each {|it| 
            if ($"($full_path)/($it.name)" | path exists) and ($"($full_path)/($it.name)/provisioning.toml" | path exists) { 
                # load provisioning.toml for info and vers
                let provisioning_data = open $"($full_path)/($it.name)/provisioning.toml"
                { task: $item, mode: ($it.name), info: $provisioning_data.info, vers: $provisioning_data.release}
            } else {
                { task: $item, mode: ($it.name), info: "", vers: ""}
            }
        } 
}
export def providers_list [
    mode?: string
]: nothing -> list {
    if $env.PROVISIONING_PROVIDERS_PATH? == null { return } 
    ls -s  $env.PROVISIONING_PROVIDERS_PATH | where {|it| (
        ($it.name | str starts-with "_") == false 
            and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path type) == "dir"
            and ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join "templates" | path exists)
        )
    } | 
    each {|it| 
        let it_path = ($env.PROVISIONING_PROVIDERS_PATH | path join $it.name | path join "provisioning.yaml") 
        if ($it_path | path exists) { 
            # load provisioning.yaml for info and vers
            let provisioning_data = (open $it_path | default {})
            let tools = match $mode {
                "list" | "selection" => ($provisioning_data | get -o tools | default {} | transpose key value| get -o key | str join ''),
                _ =>  ($provisioning_data | get -o tools | default []),
            }
            { name: ($it.name), info: ($provisioning_data | get -o info| default ""), vers: $"($provisioning_data | get -o version | default "")", tools: $tools }
        } else {
            { name: ($it.name), info: "", vers: "", source: "", site: ""}
        }
    }
}
export def taskservs_list [
]: nothing -> list {
    get_provisioning_info $env.PROVISIONING_TASKSERVS_PATH "" |
    each { |it| 
        get_provisioning_info ($env.PROVISIONING_TASKSERVS_PATH | path join $it.mode) "" 
    } | flatten 
}
export def cluster_list [
]: nothing -> list {
    get_provisioning_info $env.PROVISIONING_CLUSTERS_PATH "" |
    each { |it| 
        get_provisioning_info ($env.PROVISIONING_CLUSTER_PATH | path join $it.mode) "" 
    } | flatten | default [] 
}
export def infras_list [ 
]: nothing -> list {
    ls -s  $env.PROVISIONING_INFRA_PATH | where {|el|
        $el.type == "dir" and ($env.PROVISIONING_INFRA_PATH | path join $el.name | path join "defs" | path exists)
    } | 
    each { |it| 
        { name: $it.name, modified: $it.modified, size: $it.size}
    } | flatten | default []
}
export def on_list [
    target_list: string 
    cmd: string
    ops: string 
]: nothing -> list {
    #use utils/on_select.nu run_on_selection
    match  $target_list {
        "providers" | "p" => { 
            _print $"\n(_ansi green)PROVIDERS(_ansi reset) list: \n"
            let list_items = (providers_list "selection")
            if ($list_items | length) == 0 { 
                _print $"🛑 no items found for (_ansi cyan)providers list(_ansi reset)" 
                return []
            } 
            if $cmd == "-" { return $list_items }
            if ($cmd | is-empty) {
                _print ($list_items | to json) "json" "result" "table"
            } else { 
                if ($env | get -o PROVISIONING_OUT | default "" | is-not-empty) or $env.PROVISIONING_NO_TERMINAL { return ""}
                let selection_pos = ($list_items | each {|it| 
                    match ($it.name | str length) {
                        2..5  =>   $"($it.name)\t\t ($it.info) \tversion: ($it.vers)",
                        _  =>   $"($it.name)\t ($it.info) \tversion: ($it.vers)",
                    }
                } | input list --index ( 
                        $"(_ansi default_dimmed)Select one item for (_ansi cyan_bold)($cmd)(_ansi reset)" +
                        $" \(use arrow keys and press [enter] or [escape] to exit\)( _ansi reset)"
                    )
                )
                if $selection_pos != null { 
                    let item_selec = ($list_items | get -o $selection_pos)
                    let item_path = ($env.PROVISIONING_PROVIDERS_PATH | path join $item_selec.name)
                    if not ($item_path | path exists) { _print $"Path ($item_path) not found" }
                    (run_on_selection $cmd $item_selec.name $item_path 
                        ($item_path | path join "nulib" | path join $item_selec.name | path join "servers.nu") $env.PROVISIONING_PROVIDERS_PATH)
                }
            }
            return []
        },
        "taskservs" | "t" => { 
            _print $"\n(_ansi blue)TASKSERVICESS(_ansi reset) list: \n"
            let list_items = (taskservs_list)
            if ($list_items | length) == 0 { 
                _print $"🛑 no items found for (_ansi cyan)taskservs list(_ansi reset)" 
                return
            } 
            if $cmd == "-" { return $list_items }
            if ($cmd | is-empty) {
                _print ($list_items | to json) "json" "result" "table"
                return []
            } else { 
                if ($env | get -o PROVISIONING_OUT | default "" | is-not-empty) or $env.PROVISIONING_NO_TERMINAL { return ""}
                let selection_pos = ($list_items | each {|it| 
                    match ($it.task | str length) {
                        2..4 => $"($it.task)\t\t  ($it.mode)\t\t($it.info)\t($it.vers)",
                        5 => $"($it.task)\t\t  ($it.mode)\t\t($it.info)\t($it.vers)",
                        12 => $"($it.task)\t  ($it.mode)\t\t($it.info)\t($it.vers)",
                        15..20 => $"($it.task) ($it.mode)\t\t($it.info)\t($it.vers)",
                        _ => $"($it.task)\t  ($it.mode)\t\t($it.info)\t($it.vers)",
                    }   
                } | input list --index (
                        $"(_ansi default_dimmed)Select one item for (_ansi cyan_bold)($cmd)(_ansi reset)" + 
                        $" \(use arrow keys and press [enter] or [escape] to exit\)( _ansi reset)"
                    )
                )
                if $selection_pos != null { 
                    let item_selec = ($list_items | get -o $selection_pos)
                    let item_path = $"($env.PROVISIONING_TASKSERVS_PATH)/($item_selec.task)/($item_selec.mode)"
                    if not ($item_path | path exists) { _print $"Path ($item_path) not found" }
                    run_on_selection $cmd $item_selec.task $item_path ($item_path | path join $"install-($item_selec.task).sh") $env.PROVISIONING_TASKSERVS_PATH 
                }
            }
            return []
        },
        "clusters" | "c" => { 
            _print $"\n(_ansi purple)Cluster(_ansi reset) list: \n"
            let list_items = (cluster_list)
            if ($list_items | length) == 0 { 
                _print $"🛑 no items found for (_ansi cyan)cluster list(_ansi reset)" 
                return []
            } 
            if $cmd == "-" { return $list_items }
            if ($cmd | is-empty) {
                _print ($list_items | to json) "json" "result" "table"
            } else { 
                if ($env | get -o PROVISIONING_OUT | default "" | is-not-empty) or $env.PROVISIONING_NO_TERMINAL { return ""}
                let selection = (cluster_list | input list) 
                #print ($"(_ansi default_dimmed)Select one item for (_ansi cyan_bold)($cmd)(_ansi reset) " + 
                #        $" \(use arrow keys and press [enter] or [escape] to exit\)( _ansi reset)" )
                _print $"($cmd) ($selection)"
            }
            return []
        },
        "infras" | "i" => { 
            _print $"\n(_ansi cyan)Infrastructures(_ansi reset) list: \n"
            let list_items = (infras_list)
            if ($list_items | length) == 0 { 
                _print $"🛑 no items found for (_ansi cyan)infras list(_ansi reset)" 
                return []
            } 
            if $cmd == "-" { return $list_items }
            if ($cmd | is-empty) {
                _print ($list_items | to json) "json" "result" "table"
            } else { 
                if ($env | get -o PROVISIONING_OUT | default "" | is-not-empty) or $env.PROVISIONING_NO_TERMINAL { return ""}
                let selection_pos = ($list_items | each {|it| 
                    match ($it.name | str length) {
                        2..5 => $"($it.name)\t\t  ($it.modified) -- ($it.size)",
                        12 => $"($it.name)\t  ($it.modified) -- ($it.size)",
                        15..20 => $"($it.name) ($it.modified) -- ($it.size)",
                        _ => $"($it.name)\t  ($it.modified) -- ($it.size)",
                    }   
                } | input list --index (
                        $"(_ansi default_dimmed)Select one item for (_ansi cyan_bold)($cmd)(_ansi reset)" + 
                        $" \(use arrow keys and [enter] or [escape] to exit\)( _ansi reset)"
                    )  
                )
                if $selection_pos != null { 
                    let item_selec = ($list_items | get -o $selection_pos)
                    let item_path = $"($env.PROVISIONING_KLOUD_PATH)/($item_selec.name)"
                    if not ($item_path | path exists) { _print $"Path ($item_path) not found" }
                    run_on_selection $cmd $item_selec.name $item_path ($item_path | path join $env.PROVISIONING_DFLT_SET) $env.PROVISIONING_INFRA_PATH 
                }
            }
            return []
        },
        "help" | "h" | _ => { 
            if $target_list != "help" or $target_list != "h" {
                _print $"🛑 Not found ($env.PROVISIONING_NAME) target list option (_ansi red)($target_list)(_ansi reset)" 
            }
            _print (
                $"Use (_ansi blue_bold)($env.PROVISIONING_NAME)(_ansi reset) (_ansi green)list(_ansi reset)" + 
                $" [ providers (_ansi green)p(_ansi reset) | tasks (_ansi green)t(_ansi reset) | " + 
                $"infras (_ansi cyan)k(_ansi reset) ] to list items" + 
                $"\n(_ansi default_dimmed)add(_ansi reset) --onsel (_ansi yellow_bold)e(_ansi reset)dit | " + 
                $"(_ansi yellow_bold)v(_ansi reset)iew | (_ansi yellow_bold)l(_ansi reset)ist | (_ansi yellow_bold)t(_ansi reset)ree | " +
                $"(_ansi yellow_bold)c(_ansi reset)ode | (_ansi yellow_bold)s(_ansi reset)hell | (_ansi yellow_bold)n(_ansi reset)u"
            )
            return []
        }, 
        _ => { 
            _print $"🛑 invalid_option $list ($ops)"
            return []
        } 
    } 
}
