# shellcheck shell=dash

___X_CMD_CRON="${___X_CMD_ROOT_DATA}/cron"
___X_CMD_CRON_TZMAP="$___X_CMD_ROOT_MOD/cron/lib/tzmap"

xrc:mod:lib     cron   match ls service run util history

___x_cmd_cron___main(){
    [ "$#" -gt 0 ] ||   set -- --help

    local op="$1";      shift
    case "$op" in
        -h|--help)      ___x_cmd help -m cron "$@";    return 0 ;;

        ls|list)        ___x_cmd_cron_ls "$@" ;;

        add|rm|exec|service|match|tz|runonce|run|history)
                        ___x_cmd_cron_"$op" "$@" ;;

        *)              N=cron M="Unknown subcmd -> $op" log:ret:64 ;;
    esac
}

___x_cmd_cron_add(){
    local ns="DEFAULT"
    local name=""
    local desc=""
    local once=""
    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m cron add; return 0 ;;
            --ns)       ns="$2" ;       arg:2:shift ;;
            --name)     name="$2" ;     arg:2:shift ;;
            --desc)     desc="$2" ;     arg:2:shift ;;
            --once)     once=1 ;        shift ;;
            *)          break ;;
        esac
    done

    local cron_pat="$1"
    local cron_cmd="$2"

    if [ -z "$name" ] || [ -z "$cron_pat" ] || [ -z "$cron_cmd" ]; then
        cron:error "Usage: x cron add [--ns NS] --name <name> [--desc <desc>] [--once] <pattern> <command>"
        return 1
    fi

    ___x_cmd_cron___validate_pat "$cron_pat" || return 1

    local jobdir="$___X_CMD_CRON/$ns/job/$name"
    ___x_cmd mkdirp "$jobdir"

    if [ -f "$jobdir/cron" ]; then
        cron:error "Job already exists: $name"
        return 1
    fi

    printf '%s\n' "$cron_pat" > "$jobdir/cron"
    printf '%s\n' "$cron_cmd" > "$jobdir/cmd"
    [ -n "$desc" ] && printf '%s\n' "$desc" > "$jobdir/desc"
    [ -n "$once" ] && printf '' > "$jobdir/once"

    cron:info --ns "$ns" --pat "$cron_pat" --m:cmd "$cron_cmd" "Job '$name' added"
}

___x_cmd_cron_tz___lookup_fallback_(){
    local tz="$1"
    local name
    local posix
    [ -f "$___X_CMD_CRON_TZMAP" ] || { x_=""; return; }
    while read -r name posix; do
        [ -n "$name" ] || continue
        case "$name" in
            \#*) continue ;;
        esac
        [ "$name" = "$tz" ] && { x_="$posix"; return; }
    done < "$___X_CMD_CRON_TZMAP"
    x_=""
}

___x_cmd_cron_tz(){
    local ns="DEFAULT"
    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m cron tz; return 0 ;;
            --ns)       ns="$2" ; arg:2:shift ;;
            *)          break ;;
        esac
    done

    local tzval="$1"

    ___x_cmd mkdirp "$___X_CMD_CRON/$ns"

    if [ -z "$tzval" ]; then
        if [ -f "$___X_CMD_CRON/$ns/tz" ]; then
            read -r tzval < "$___X_CMD_CRON/$ns/tz"
            cron:info "Current timezone: $tzval"
            printf '%s\n' "$tzval"
        else
            cron:info "No timezone set"
        fi
    else
        # If it looks like an IANA name and the system lacks tzdata, warn
        case "$tzval" in
            */*)
                if [ ! -f "/usr/share/zoneinfo/$tzval" ]; then
                    local x_
                    ___x_cmd_cron_tz___lookup_fallback_ "$tzval"
                    if [ -n "$x_" ]; then
                        cron:warn "System tzdata missing, timezone may not take effect. Recommended: $x_"
                    else
                        cron:warn "System tzdata missing, timezone may not take effect"
                    fi
                fi
                ;;
        esac
        printf '%s\n' "$tzval" > "$___X_CMD_CRON/$ns/tz"
    fi
}


___x_cmd_cron_rm(){
    local ns="DEFAULT"
    local name=""
    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m cron rm; return 0 ;;
            --ns)       ns="$2" ; arg:2:shift ;;
            --name)     name="$2" ; arg:2:shift ;;
            *)          break ;;
        esac
    done

    # Fallback to positional argument for backward compatibility
    if [ -z "$name" ]; then
        name="$1"
    fi

    if [ -z "$name" ]; then
        cron:error "Usage: x cron rm [--ns NS] --name <name>"
        return 1
    fi

    local jobdir="$___X_CMD_CRON/$ns/job/$name"

    if [ ! -d "$jobdir" ]; then
        cron:error "Job not found: $name"
        return 1
    fi

    ___x_cmd rmrf "$jobdir"
    ___x_cmd rmrf "$___X_CMD_CRON/$ns/run/$name"
    ___x_cmd rmrf "$___X_CMD_CRON/$ns/state/$name"
}

___x_cmd_cron_exec(){
    local ns="DEFAULT"
    while [ $# -gt 0 ]; do
        case "$1" in
            --help|-h)  ___x_cmd help -m cron exec; return 0 ;;
            --ns)       ns="$2" ; arg:2:shift ;;
            *)          break ;;
        esac
    done

    local name="$1"

    if [ -z "$name" ]; then
        cron:error "Usage: x cron exec [--ns NS] <name>"
        return 1
    fi

    local jobdir="$___X_CMD_CRON/$ns/job/$name"

    if [ ! -d "$jobdir" ]; then
        cron:error "Job not found: $name"
        return 1
    fi

    if [ ! -f "$jobdir/cmd" ]; then
        cron:error "Job has no cmd: $name"
        return 1
    fi

    # Record execution state
    local state_dir
    local epoch_dir
    local x_

    state_dir="$___X_CMD_CRON/$ns/state/$name"
    ___x_cmd mkdirp "$state_dir"
    ___x_cmd_cron_history___cleanup "$state_dir" 10

    ___x_cmd epoch get_
    epoch_dir="$state_dir/$x_"
    ___x_cmd mkdirp "$epoch_dir"

    cron:info "Execute job $name"

    # Execute and capture output
    . "$jobdir/cmd" >"$epoch_dir/out" 2>"$epoch_dir/err"
    local exit_code=$?

    # Record end time and exit code
    ___x_cmd epoch get > "$epoch_dir/end_time"
    printf '%s\n' "$exit_code" > "$epoch_dir/exit_code"

    # Show result via history detail formatter
    ___x_cmd_cron_history___detail "$epoch_dir" "$x_"

    if [ "$exit_code" -eq 0 ]; then
        cron:info "Job $name completed successfully"
    else
        cron:warn "Job $name failed with exit_code=$exit_code"
    fi
    return $exit_code
}
