use dag-executor.nu [load-dag]
use ../workspace/state.nu [state-read, state-node-get]
use ../lib_provisioning/config/accessor.nu *
use ../lib_provisioning/utils/settings.nu [find_get_settings, settings_with_env]

def state-icon [s: string]: nothing -> string {
    match $s {
        "completed" => $"(_ansi green)✅(_ansi reset)",
        "running"   => $"(_ansi yellow)🔄(_ansi reset)",
        "failed"    => $"(_ansi red)❌(_ansi reset)",
        "blocked"   => $"(_ansi red_dimmed)⊘(_ansi reset)",
        _           => $"(_ansi default_dimmed)⏳(_ansi reset)",
    }
}

def state-col [s: string]: nothing -> string {
    match $s {
        "completed" => (_ansi green),
        "running"   => (_ansi yellow),
        "failed"    => (_ansi red),
        "blocked"   => (_ansi red_dimmed),
        _           => (_ansi default_dimmed),
    }
}

def fmt-ts [ts: string]: nothing -> string {
    if ($ts | is-empty) { "—" } else { $ts | str replace "T" " " | str replace "Z" "" }
}

# Show DAG formula execution progress — which taskservs completed, pending, failed
export def "main status" [
    --infra (-i): string    = ""
    --settings (-s): string = ""
    --server: string        = ""
] {
    let curr_settings = (settings_with_env (find_get_settings --infra $infra --settings $settings))
    let workspace_path = ($curr_settings.src_path? | default $env.PWD)
    let dag = (load-dag $curr_settings)

    if not $dag.has_dag {
        _print "No DAG found — no formula state to show."
        return
    }

    let st = (state-read $workspace_path)

    for formula in $dag.formulas {
        if ($server | is-not-empty) and $formula.server != $server { continue }

        let all_done = ($formula.nodes | all {|n|
            let ns = (state-node-get $workspace_path $formula.server $n.taskserv.name)
            $ns.state == "completed"
        })
        let tag = if $all_done {
            $"(_ansi green)[complete](_ansi reset)"
        } else {
            $"(_ansi yellow)[in progress](_ansi reset)"
        }

        _print $"▶ (_ansi green_bold)($formula.id)(_ansi reset) on (_ansi cyan_bold)($formula.server)(_ansi reset) ($tag)"

        for node in $formula.nodes {
            let ns       = (state-node-get $workspace_path $formula.server $node.taskserv.name)
            let icon     = (state-icon $ns.state)
            let col      = (state-col  $ns.state)
            let name_pad = ($node.taskserv.name | fill -a l -w 20)
            let st_pad   = ($ns.state           | fill -a l -w 10)
            let ts       = if $ns.state == "completed" { fmt-ts $ns.ended_at } else { "" }
            let extra    = if ($ns.blocker? | default "" | is-not-empty) {
                $" ← blocked by (_ansi red)($ns.blocker)(_ansi reset)"
            } else { "" }
            _print $"  ($icon) ($col)($name_pad)(_ansi reset) ($col)($st_pad)(_ansi reset) ($ts)($extra)"
        }
        _print ""
    }
}

# List all taskservs in the DAG with their state
export def "main list" [
    --infra (-i): string    = ""
    --settings (-s): string = ""
    --server: string        = ""
    --out: string           = ""
] {
    let curr_settings = (settings_with_env (find_get_settings --infra $infra --settings $settings))
    let workspace_path = ($curr_settings.src_path? | default $env.PWD)
    let dag = (load-dag $curr_settings)

    if not $dag.has_dag {
        _print "No DAG found."
        return
    }

    let rows = ($dag.formulas | each {|formula|
        if ($server | is-not-empty) and $formula.server != $server { [] } else {
            $formula.nodes | each {|node|
                let ns = (state-node-get $workspace_path $formula.server $node.taskserv.name)
                {
                    taskserv:   $node.taskserv.name,
                    server:     $formula.server,
                    state:      $ns.state,
                    profile:    ($node.taskserv.profile? | default "default"),
                    depends_on: ($node.depends_on? | default [] | each {|d| $d.node_id } | str join ","),
                    ended:      (fmt-ts $ns.ended_at),
                    actor:      ($ns.actor?.identity? | default ""),
                }
            }
        }
    } | flatten)

    if $out == "json" { $rows | to json; return }
    if $out == "yaml" { $rows | to yaml; return }

    _print $"(_ansi default_dimmed)TASKSERV             SERVER             STATE       PROFILE    DEPENDS-ON           ENDED(_ansi reset)"
    for row in $rows {
        let col  = (state-col $row.state)
        let icon = (state-icon $row.state)
        _print (
            $"($icon) ($col)($row.taskserv   | fill -a l -w 20)(_ansi reset)" +
            $"  (_ansi cyan)($row.server    | fill -a l -w 17)(_ansi reset)" +
            $"  ($col)($row.state      | fill -a l -w 10)(_ansi reset)" +
            $"  ($row.profile     | fill -a l -w 10)" +
            $"  ($row.depends_on  | fill -a l -w 20)" +
            $"  ($row.ended)"
        )
    }
}
