#compdef go_task
typeset -A opt_args
GO_TASK_CMD="${GO_TASK_EXE:-go-task}"
compdef _go_task "$GO_TASK_CMD"

_GO_TASK_COMPLETION_LIST_OPTION="${GO_TASK_COMPLETION_LIST_OPTION:---list-all}"

# Check if an experiment is enabled
function __go_task_is_experiment_enabled() {
    local experiment=$1
    go-task --experiments 2>/dev/null | grep -q "^\* ${experiment}:.*on"
}

# Listing commands from Taskfile.yml
function __go_task_list() {
    local -a scripts cmd
    local -i enabled=0
    local taskfile item task desc

    cmd=($GO_TASK_CMD)
    taskfile=${(Qv)opt_args[(i)-t|--taskfile]}
    taskfile=${taskfile//\~/$HOME}

    for arg in "${words[@]:0:$CURRENT}"; do
        if [[ "$arg" = "--" ]]; then
            # Use default completion for words after `--` as they are CLI_ARGS.
            _default
            return 0
        fi
    done

    if [[ -n "$taskfile" && -f "$taskfile" ]]; then
        cmd+=(--taskfile "$taskfile")
    fi

    # Check if global flag is set
    if (( ${+opt_args[-g]} || ${+opt_args[--global]} )); then
        cmd+=(--global)
    fi

    if output=$("${cmd[@]}" $_GO_TASK_COMPLETION_LIST_OPTION 2>/dev/null); then
        enabled=1
    fi

    (( enabled )) || return 0

    scripts=()

    # Read zstyle verbose option (default = true via -T)
    local show_desc
    zstyle -T ":completion:${curcontext}:" verbose && show_desc=true || show_desc=false

    for item in "${(@)${(f)output}[2,-1]#\* }"; do
        task="${item%%:[[:space:]]*}"

        if [[ "$show_desc" == "true" ]]; then
            local desc="${item##[^[:space:]]##[[:space:]]##}"
            scripts+=( "${task//:/\\:}:$desc" )
        else
            scripts+=( "$task" )
        fi
    done

    if [[ "$show_desc" == "true" ]]; then
        _describe 'Task to run' scripts
    else
        compadd -Q -a scripts
    fi
}

_go_task() {
    local -a standard_args operation_args

    standard_args=(
        '(-C --concurrency)'{-C,--concurrency}'[limit number of concurrent tasks]: '
        '(-p --parallel)'{-p,--parallel}'[run command-line tasks in parallel]'
        '(-F --failfast)'{-F,--failfast}'[when running tasks in parallel, stop all tasks if one fails]'
        '(-f --force)'{-f,--force}'[run even if task is up-to-date]'
        '(-c --color)'{-c,--color}'[colored output]'
        '(--completion)--completion[generate shell completion script]:shell:(bash zsh fish powershell)'
        '(-d --dir)'{-d,--dir}'[dir to run in]:execution dir:_dirs'
        '(--disable-fuzzy)--disable-fuzzy[disable fuzzy matching for task names]'
        '(-n --dry)'{-n,--dry}'[compiles and prints tasks without executing]'
        '(--dry)--dry[dry-run mode, compile and print tasks only]'
        '(-x --exit-code)'{-x,--exit-code}'[pass-through exit code of task command]'
        '(--experiments)--experiments[list available experiments]'
        '(-g --global)'{-g,--global}'[run global Taskfile from home directory]'
        '(--insecure)--insecure[allow insecure Taskfile downloads]'
        '(-I --interval)'{-I,--interval}'[interval to watch for changes]:duration: '
        '(-j --json)'{-j,--json}'[format task list as JSON]'
        '(--nested)--nested[nest namespaces when listing as JSON]'
        '(--no-status)--no-status[ignore status when listing as JSON]'
        '(--interactive)--interactive[prompt for missing required variables]'
        '(-o --output)'{-o,--output}'[set output style]:style:(interleaved group prefixed)'
        '(--output-group-begin)--output-group-begin[message template before grouped output]:template text: '
        '(--output-group-end)--output-group-end[message template after grouped output]:template text: '
        '(--output-group-error-only)--output-group-error-only[hide output from successful tasks]'
        '(-s --silent)'{-s,--silent}'[disable echoing]'
        '(--sort)--sort[set task sorting order]:order:(default alphanumeric none)'
        '(--status)--status[exit non-zero if supplied tasks not up-to-date]'
        '(--summary)--summary[show summary\: field from tasks instead of running them]'
        '(-t --taskfile)'{-t,--taskfile}'[specify a different taskfile]:taskfile:_files'
        '(-v --verbose)'{-v,--verbose}'[verbose mode]'
        '(-w --watch)'{-w,--watch}'[watch-mode for given tasks, re-run when inputs change]'
        '(-y --yes)'{-y,--yes}'[assume yes to all prompts]'
    )

    # Experimental flags (dynamically added based on enabled experiments)
    # Options (modify behavior)
    if __go_task_is_experiment_enabled "GENTLE_FORCE"; then
        standard_args+=('(--force-all)--force-all[force execution of task and all dependencies]')
    fi

    if __go_task_is_experiment_enabled "REMOTE_TASKFILES"; then
        standard_args+=(
            '(--offline --download)--offline[use only local or cached Taskfiles]'
            '(--timeout)--timeout[timeout for remote Taskfile downloads]:duration: '
            '(--expiry)--expiry[cache expiry duration]:duration: '
            '(--remote-cache-dir)--remote-cache-dir[directory to cache remote Taskfiles]:cache dir:_dirs'
            '(--cacert)--cacert[custom CA certificate for TLS]:file:_files'
            '(--cert)--cert[client certificate for mTLS]:file:_files'
            '(--cert-key)--cert-key[client certificate private key]:file:_files'
        )
    fi

    operation_args=(
        # Task names completion (can be specified multiple times)
        '(operation)*: :__go_task_list'
        # Operational args completion (mutually exclusive)
        + '(operation)'
            '(*)'{-l,--list}'[list describable tasks]'
            '(*)'{-a,--list-all}'[list all tasks]'
            '(*)'{-i,--init}'[create new Taskfile.yml]'
            '(- *)'{-h,--help}'[show help]'
            '(- *)--version[show version and exit]'
    )

    # Experimental operations (dynamically added based on enabled experiments)
    if __go_task_is_experiment_enabled "REMOTE_TASKFILES"; then
        standard_args+=(
            '(--offline --clear-cache)--download[download remote Taskfile]'
        )
        operation_args+=(
            '(* --download)--clear-cache[clear remote Taskfile cache]'
        )
    fi

    _arguments -S $standard_args $operation_args
}

# don't run the completion function when being source-ed or eval-ed
if [ "$funcstack[1]" = "_task" ]; then
    _go_task "$@"
fi
