#!/usr/bin/env bash

_dayoa_bin_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
export SNAKEMAKE_SINGULARITY_CMD="${_dayoa_bin_dir}/dayoa_apptainer"

if [[ "${1:-}" == "--version" ]]; then
    python -c 'from importlib.metadata import version; print("daylily-omics-analysis " + version("daylily-omics-analysis"))'
    exit $?
fi

timestamp=$(date -u +%Y%m%dT%H%M%SZ)

CONFIG_FILE=~/.config/daylily/daylily_cli_global.yaml
configured_tmpdir=$(yq -r '.daylily.sentieon_tmpdir' "$CONFIG_FILE")
export TMPDIR="${DAYOA_RUNTIME_TMPDIR:-$configured_tmpdir}"
mkdir -p "$TMPDIR";
export TMP="$TMPDIR"
export TEMP="$TMPDIR"

if [[ "${DAY_REMOTE_EXE:-}" == "remote" ]]; then
    echo "Remote call detected. Activating conda hack"
    . "$HOME/miniconda3/etc/profile.d/conda.sh"
    export PATH="/home/ubuntu/miniconda3/bin:$PATH"
    conda activate DAYOA
fi

# Snakemake invokes conda from a child shell, where the parent shell function is
# unavailable. Keep the executable selected by the active conda installation on PATH.
if [[ -n "${CONDA_EXE:-}" ]]; then
    if [[ ! -x "$CONDA_EXE" ]]; then
        echo "ERROR: CONDA_EXE is not executable: $CONDA_EXE" >&2
        exit 34
    fi
    export PATH="$PATH:$(dirname -- "$CONDA_EXE")"
fi

if [[ -z "${DAY_ROOT:-}" || -z "${DAY_PROFILE:-}" || -z "${DAY_PROFILE_DIR:-}" ]]; then
    colr "ERROR: . dayiniy && day-activate [local|slurm] needs to have been run prior to day-run."  "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 33
fi
if [[ ! -d "$DAY_PROFILE_DIR" ]]; then
    colr "ERROR: Profile directory: $DAY_PROFILE_DIR does not exist." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 3
fi

profile_env_script="$DAY_PROFILE_DIR/templates/profile_env.bash"
if [[ -f "$DAY_PROFILE_DIR/profile_env.bash" ]]; then
    profile_env_script="$DAY_PROFILE_DIR/profile_env.bash"
fi
if [[ ! -f "$profile_env_script" ]]; then
    colr "ERROR: Profile environment script not found for $DAY_PROFILE_DIR." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 3
fi
source "$profile_env_script"
profile_env_ret_code=$?
if [[ "$profile_env_ret_code" != "0" ]]; then
    colr "ERROR: Profile environment script failed before Snakemake launch: $profile_env_script" "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit "$profile_env_ret_code"
fi

if [[ -z "$DAY_GENOME_BUILD" ]]; then
    colr "ERROR: Genome build not set. Please run 'dy-g [b37|hg38]'." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 3
fi

source bin/util/profile_freshness_warn.bash
if [[ "$?" == "3" ]]; then
    colr "ERROR: source bin/util/profile_freshness_warn.bash"  "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    return 4
fi

# Check if we're in the correct root
if [[ "$(pwd)" != "$DAY_ROOT"* ]]; then
    colr "|||<<<
___________________

    You are not in the correct DAY_ROOT

    **>> DETECTED:     $PWD

    **>> EXPECTED:     $DAY_ROOT

    
___________________

    >>>|||" "$DY_ET0" "$DY_EB0" "$DY_ES1" 1>&2
    echo ""
    echo "Please run 'day-deactivate' and 'day-activate' from the intended analysis deployment directory."
    exit 3
fi



# ---------------------------------------------------------------------------
# Auto-detect aligner / deduper config from target rule names on the CLI.
# If the user specifies target rules like dedup_doppelmark or
# produce_bwa_mem2_sort_bam, we inject the corresponding --config values
# so downstream expand() calls see a populated ALIGNERS / DDUP list.
# Explicit --config aligners=... / dedupers=... always takes priority.
# ---------------------------------------------------------------------------
_dedup_codes=()
_aligner_codes=()
_snv_caller_codes=()
_sv_caller_codes=()
_has_dedupers_config=false
_has_aligners_config=false
_has_snv_callers_config=false
_has_sv_callers_config=false
_is_dry_run=false
_is_unlock=false
_sentieon_start_jitter=false
_sentieon_start_jitter_jobs=""
_isolated_conda_prefix=false
_has_user_conda_prefix=false
_produce_ursa_manifest=false
_produce_rulegraph=false
_produce_filegraph=false
_produce_dag=false
_ursa_manifest_excludes=()
_seen_produce_ursa_manifest=false
_seen_produce_rulegraph=false
_seen_produce_filegraph=false
_seen_produce_dag=false
_has_native_preflight_action=false
_dy_forward_args=()
_DY_TARGET_REGISTRY="${DAY_ROOT:-.}/config/workflow_target_aliases.tsv"

_dy_add_auto_code() {
    local _kind="$1"
    local _code="$2"
    case "$_kind" in
        aligner)     _aligner_codes+=("$_code") ;;
        deduper)     _dedup_codes+=("$_code") ;;
        snv_caller)  _snv_caller_codes+=("$_code") ;;
        sv_caller)   _sv_caller_codes+=("$_code") ;;
    esac
}

_dy_add_registry_target_codes() {
    local _target="$1"
    local _kind="$2"
    local _rtarget _rkind _rcode _rstatus _rdelegates
    [[ -f "$_DY_TARGET_REGISTRY" ]] || return 0
    while IFS=$'\t' read -r _rtarget _rkind _rcode _rstatus _rdelegates; do
        [[ "$_rtarget" == "$_target" && "$_rkind" == "$_kind" ]] || continue
        if [[ "$_rcode" == "all" ]]; then
            local _atarget _akind _acode _astatus _adelegates
            while IFS=$'\t' read -r _atarget _akind _acode _astatus _adelegates; do
                [[ "$_akind" == "$_kind" && "$_astatus" == "current" && "$_acode" != "all" ]] || continue
                _dy_add_auto_code "$_kind" "$_acode"
            done < "$_DY_TARGET_REGISTRY"
        else
            _dy_add_auto_code "$_kind" "$_rcode"
        fi
    done < "$_DY_TARGET_REGISTRY"
}

_dy_unique_csv() {
    printf '%s\n' "$@" | awk 'NF && !seen[$0]++' | paste -sd, -
}

_dy_require_positive_int() {
    local _value="$1"
    local _name="$2"
    if [[ ! "$_value" =~ ^[1-9][0-9]*$ ]]; then
        colr "ERROR: $_name must be a positive integer; got '$_value'." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        exit 64
    fi
}

_dy_set_producer_option() {
    local _option="$1"
    local _value
    _value=$(printf '%s' "$2" | tr '[:upper:]' '[:lower:]')
    if [[ "$_value" != "true" && "$_value" != "false" ]]; then
        colr "ERROR: $_option requires true or false; got '$2'." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        exit 64
    fi
    case "$_option" in
        --produce-ursa-manifest)
            if [[ "$_seen_produce_ursa_manifest" == "true" ]]; then
                colr "ERROR: $_option may be specified only once." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _seen_produce_ursa_manifest=true
            _produce_ursa_manifest="$_value"
            ;;
        --produce-rulegraph)
            if [[ "$_seen_produce_rulegraph" == "true" ]]; then
                colr "ERROR: $_option may be specified only once." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _seen_produce_rulegraph=true
            _produce_rulegraph="$_value"
            ;;
        --produce-filegraph)
            if [[ "$_seen_produce_filegraph" == "true" ]]; then
                colr "ERROR: $_option may be specified only once." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _seen_produce_filegraph=true
            _produce_filegraph="$_value"
            ;;
        --produce-dag)
            if [[ "$_seen_produce_dag" == "true" ]]; then
                colr "ERROR: $_option may be specified only once." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _seen_produce_dag=true
            _produce_dag="$_value"
            ;;
    esac
}

while [[ "$#" -gt 0 ]]; do
    _arg="$1"
    case "$_arg" in
        --ursa-manifest-exclude)
            if [[ "$#" -lt 2 || -z "$2" ]]; then
                colr "ERROR: $_arg requires a non-empty glob pattern." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _ursa_manifest_excludes+=("$2")
            shift 2
            continue
            ;;
        --ursa-manifest-exclude=*)
            _value="${_arg#*=}"
            if [[ -z "$_value" ]]; then
                colr "ERROR: --ursa-manifest-exclude requires a non-empty glob pattern." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _ursa_manifest_excludes+=("$_value")
            shift
            continue
            ;;
        --produce-ursa-manifest|--produce-rulegraph|--produce-filegraph|--produce-dag)
            if [[ "$#" -lt 2 ]]; then
                colr "ERROR: $_arg requires true or false." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _dy_set_producer_option "$_arg" "$2"
            shift 2
            continue
            ;;
        --produce-ursa-manifest=*|--produce-rulegraph=*|--produce-filegraph=*|--produce-dag=*)
            _dy_set_producer_option "${_arg%%=*}" "${_arg#*=}"
            shift
            continue
            ;;
        --isolated-conda-prefix)
            _isolated_conda_prefix=true
            shift
            continue
            ;;
        --conda-prefix)
            if [[ "$#" -lt 2 ]]; then
                colr "ERROR: --conda-prefix requires a value." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _has_user_conda_prefix=true
            _dy_forward_args+=("$_arg" "$2")
            shift 2
            continue
            ;;
        --conda-prefix=*)
            _has_user_conda_prefix=true
            _dy_forward_args+=("$_arg")
            shift
            continue
            ;;
        --sentieon-start-jitter)
            _sentieon_start_jitter=true
            shift
            continue
            ;;
        -j|--jobs|--cores)
            if [[ "$#" -lt 2 ]]; then
                colr "ERROR: $_arg requires a positive integer value." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
                exit 64
            fi
            _dy_require_positive_int "$2" "$_arg"
            _sentieon_start_jitter_jobs="$2"
            _dy_forward_args+=("$_arg" "$2")
            shift 2
            continue
            ;;
        -j[1-9]*)
            _sentieon_start_jitter_jobs="${_arg#-j}"
            _dy_require_positive_int "$_sentieon_start_jitter_jobs" "-j"
            _dy_forward_args+=("$_arg")
            shift
            continue
            ;;
        --jobs=*|--cores=*)
            _sentieon_start_jitter_jobs="${_arg#*=}"
            _dy_require_positive_int "$_sentieon_start_jitter_jobs" "${_arg%%=*}"
            _dy_forward_args+=("$_arg")
            shift
            continue
            ;;
    esac
    _dy_forward_args+=("$_arg")
    shift
done

if [[ "$_sentieon_start_jitter" == "true" ]]; then
    if [[ -z "$_sentieon_start_jitter_jobs" ]]; then
        colr "ERROR: --sentieon-start-jitter requires an explicit -j/--jobs/--cores positive integer." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        exit 64
    fi
    export DAYOA_SENTIEON_START_JITTER_MAX_SECONDS="160"
    colr "...SENTIEON-JITTER: max_seconds=${DAYOA_SENTIEON_START_JITTER_MAX_SECONDS} (jobs=${_sentieon_start_jitter_jobs})" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
else
    unset DAYOA_SENTIEON_START_JITTER_MAX_SECONDS
fi

if [[ "$_isolated_conda_prefix" == "true" ]]; then
    if [[ "$_has_user_conda_prefix" == "true" ]]; then
        colr "ERROR: --isolated-conda-prefix cannot be combined with --conda-prefix." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        exit 64
    fi
    _dayoa_isolated_conda_prefix="$PWD/.snakemake/conda"
    mkdir -p "$_dayoa_isolated_conda_prefix"
    _dy_forward_args=("--conda-prefix" "$_dayoa_isolated_conda_prefix" "${_dy_forward_args[@]}")
    colr "...CONDA-PREFIX: isolated=${_dayoa_isolated_conda_prefix}" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
fi

for _arg in "${_dy_forward_args[@]}"; do
    _dy_add_registry_target_codes "$_arg" aligner
    _dy_add_registry_target_codes "$_arg" deduper
    _dy_add_registry_target_codes "$_arg" snv_caller
    _dy_add_registry_target_codes "$_arg" sv_caller
    # Check if user already specified these config keys
    case "$_arg" in
        dedupers=*)      _has_dedupers_config=true      ;;
        aligners=*)      _has_aligners_config=true       ;;
        snv_callers=*)   _has_snv_callers_config=true    ;;
        sv_callers=*)    _has_sv_callers_config=true     ;;
    esac
    # Detect dry-run flags
    case "$_arg" in
        -n|--dry-run|--dryrun)  _is_dry_run=true  ;;
    esac
    case "$_arg" in
        --unlock)  _is_unlock=true  ;;
    esac
    case "$_arg" in
        --dag|--rulegraph|--filegraph|--summary|--detailed-summary)
            _has_native_preflight_action=true
            ;;
    esac
done

_produces_preflight_artifacts=false
if [[ "$_produce_ursa_manifest" == "true" || "$_produce_rulegraph" == "true" || \
      "$_produce_filegraph" == "true" || "$_produce_dag" == "true" ]]; then
    _produces_preflight_artifacts=true
fi
if [[ "$_produces_preflight_artifacts" == "true" && "$_is_unlock" == "true" ]]; then
    colr "ERROR: dy-r producer options cannot be combined with --unlock." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 64
fi
if [[ "$_produces_preflight_artifacts" == "true" && "$_has_native_preflight_action" == "true" ]]; then
    colr "ERROR: dy-r producer options cannot be combined with native --summary/--dag/--rulegraph/--filegraph actions." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 64
fi
if [[ "${#_ursa_manifest_excludes[@]}" -gt 0 && "$_produce_ursa_manifest" != "true" ]]; then
    colr "ERROR: --ursa-manifest-exclude requires --produce-ursa-manifest true." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    exit 64
fi

# Export auto-detected config as environment variables for common.smk.
# This avoids Snakemake's --config nargs="*" consuming target names.
if [[ ${#_dedup_codes[@]} -gt 0 ]] && [[ "$_has_dedupers_config" == "false" ]]; then
    _dedup_csv=$(_dy_unique_csv "${_dedup_codes[@]}")
    export _DY_AUTO_DEDUPERS="$_dedup_csv"
    colr "...AUTO-CONFIG: dedupers=${_dedup_csv} (from target rules → env)" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
fi

if [[ ${#_aligner_codes[@]} -gt 0 ]] && [[ "$_has_aligners_config" == "false" ]]; then
    _aligner_csv=$(_dy_unique_csv "${_aligner_codes[@]}")
    export _DY_AUTO_ALIGNERS="$_aligner_csv"
    colr "...AUTO-CONFIG: aligners=${_aligner_csv} (from target rules → env)" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
fi

if [[ ${#_snv_caller_codes[@]} -gt 0 ]] && [[ "$_has_snv_callers_config" == "false" ]]; then
    _snv_csv=$(_dy_unique_csv "${_snv_caller_codes[@]}")
    export _DY_AUTO_SNV_CALLERS="$_snv_csv"
    colr "...AUTO-CONFIG: snv_callers=${_snv_csv} (from target rules → env)" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
fi

if [[ ${#_sv_caller_codes[@]} -gt 0 ]] && [[ "$_has_sv_callers_config" == "false" ]]; then
    _sv_csv=$(_dy_unique_csv "${_sv_caller_codes[@]}")
    export _DY_AUTO_SV_CALLERS="$_sv_csv"
    colr "...AUTO-CONFIG: sv_callers=${_sv_csv} (from target rules → env)" "$DY_IT1" "$DY_IB1" "$DY_IS1" 1>&2
fi

# Build the snakemake command — targets pass through unchanged.
snakecmd_init=("snakemake" "--profile=$DAY_PROFILE_DIR" "${_dy_forward_args[@]}")
snakecmd=()
for _arg in "${snakecmd_init[@]}"; do
    if [[ "$_arg" == "--keep-temp" ]]; then
        snakecmd+=("--notemp")
    else
        snakecmd+=("$_arg")
    fi
done

_dayoa_analysis_root="$DAY_ROOT"
if [[ "$(basename "$DAY_ROOT")" == "daylily-omics-analysis" ]]; then
    _dayoa_analysis_root="$(dirname "$DAY_ROOT")"
fi
_dayoa_write_operation=false
_dayoa_ursa_manifest=""
_dayoa_ursa_manifest_finalized=false
_dayoa_logs_before=()

_dayoa_guard_if_analysis_results() {
    local _operation="$1"
    local _intent="$2"
    if [[ "$_dayoa_analysis_root" != *"/analysis_results/"* ]]; then
        return 0
    fi
    if ! command -v dyec >/dev/null 2>&1; then
        colr "ERROR: dy-r in analysis_results requires dyec analysis guard for agent lock enforcement." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        exit 66
    fi
    if [[ "$_operation" == "read" ]]; then
        dyec analysis visit \
            --analysis-root "$_dayoa_analysis_root" \
            --mode read \
            --intent "$_intent" \
            --note "dy-r read/dry-run visit"
    else
        dyec analysis guard \
            --analysis-root "$_dayoa_analysis_root" \
            --operation "$_operation" \
            --intent "$_intent"
    fi
}

if [[ "$_is_unlock" == "true" ]]; then
    _dayoa_guard_if_analysis_results "unlock" "dy-r --unlock: ${snakecmd[*]}"
elif [[ "$_is_dry_run" == "true" && "$_produces_preflight_artifacts" != "true" ]]; then
    _dayoa_guard_if_analysis_results "read" "dy-r dry-run/status: ${snakecmd[*]}"
else
    _dayoa_write_operation=true
    _dayoa_guard_if_analysis_results "write" "dy-r workflow/artifact write: ${snakecmd[*]}"
fi

_dayoa_snapshot_native_logs() {
    _dayoa_logs_before=()
    if [[ -d ".snakemake/log" ]]; then
        while IFS= read -r _log; do
            [[ -n "$_log" ]] && _dayoa_logs_before+=("$_log")
        done < <(find .snakemake/log -maxdepth 1 -type f -name '*.snakemake.log' -print | sort)
    fi
}

_dayoa_is_prior_log() {
    local _candidate="$1"
    local _prior
    for _prior in "${_dayoa_logs_before[@]}"; do
        [[ "$_candidate" == "$_prior" ]] && return 0
    done
    return 1
}

_dayoa_finalize_ursa_manifest() {
    local _workflow_rc="$1"
    local _finalize_rc=0
    local _log
    local _reason=""
    local _new_logs=()
    local _finalize_cmd=()
    local _exclude
    if [[ -z "$_dayoa_ursa_manifest" || "$_dayoa_ursa_manifest_finalized" == "true" ]]; then
        return 0
    fi
    if [[ "$_is_dry_run" == "true" ]]; then
        _reason="no_native_execution_log_for_dry_run"
    else
        if [[ -d ".snakemake/log" ]]; then
            while IFS= read -r _log; do
                if [[ -n "$_log" ]] && ! _dayoa_is_prior_log "$_log"; then
                    _new_logs+=("$_log")
                fi
            done < <(find .snakemake/log -maxdepth 1 -type f -name '*.snakemake.log' -print | sort)
        fi
        if [[ "${#_new_logs[@]}" -eq 1 ]]; then
            _finalize_cmd=(python -m daylily_omics_analysis.ursa_artifacts finalize-manifest \
                --manifest "$_dayoa_ursa_manifest" \
                --analysis-root "$PWD" \
                --log-path "${_new_logs[0]}")
            for _exclude in "${_ursa_manifest_excludes[@]}"; do
                _finalize_cmd+=(--exclude "$_exclude")
            done
            "${_finalize_cmd[@]}" || _finalize_rc=$?
        elif [[ "${#_new_logs[@]}" -eq 0 ]]; then
            _reason="native_execution_log_not_created"
        else
            _reason="multiple_native_execution_logs_detected"
        fi
    fi
    if [[ -n "$_reason" ]]; then
        _finalize_cmd=(python -m daylily_omics_analysis.ursa_artifacts finalize-manifest \
            --manifest "$_dayoa_ursa_manifest" \
            --analysis-root "$PWD" \
            --reason "$_reason")
        for _exclude in "${_ursa_manifest_excludes[@]}"; do
            _finalize_cmd+=(--exclude "$_exclude")
        done
        "${_finalize_cmd[@]}" || _finalize_rc=$?
        if [[ "$_workflow_rc" -eq 0 && "$_is_dry_run" != "true" ]]; then
            _finalize_rc=70
        fi
    fi
    if [[ "$_finalize_rc" -eq 0 ]]; then
        _dayoa_ursa_manifest_finalized=true
    fi
    return "$_finalize_rc"
}

# A live controller owns the analysis-root write interval. Release that lock on
# every normal shell exit, including a nonzero workflow result. SIGKILL remains
# intentionally unrecoverable and requires the explicit takeover flow.
_dayoa_live_exit_cleanup() {
    local _rc=$?
    trap - EXIT

    if [[ -n "$_dayoa_ursa_manifest" && "$_dayoa_ursa_manifest_finalized" != "true" ]]; then
        if ! _dayoa_finalize_ursa_manifest "$_rc"; then
            colr "WARNING: dy-r could not finalize $_dayoa_ursa_manifest during exit cleanup." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        fi
    fi

    # Clear the Snakemake lock before releasing the analysis-root lock so a new
    # controller cannot start while cleanup from the old controller is racing.
    if ! timeout "${DAYOA_UNLOCK_TIMEOUT_SECONDS:-120}" \
        snakemake --unlock --profile "$DAY_PROFILE_DIR" \
        >> ./unlock_fails.log 2>&1; then
        colr "WARNING: dy-r could not clear the Snakemake working-directory lock within ${DAYOA_UNLOCK_TIMEOUT_SECONDS:-120}s after rc=${_rc}; see ./unlock_fails.log." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
    fi

    if [[ "$_dayoa_analysis_root" == *"/analysis_results/"* ]]; then
        if ! dyec analysis lock release \
            --analysis-root "$_dayoa_analysis_root" \
            --human-requestor "${DAYOA_HUMAN_REQUESTOR:-$USER}" \
            --note "dy-r write operation exited rc=${_rc}"; then
            colr "WARNING: dy-r failed to release the analysis-root write lock for $_dayoa_analysis_root after rc=${_rc}." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        fi
    fi

    exit "$_rc"
}

# This ensures the snakedir is unlocked and the controller-owned write lock is
# released after any successful or failed dy-r write operation.
if [[ "$_dayoa_write_operation" == "true" && "$_is_unlock" != "true" ]]; then
    trap _dayoa_live_exit_cleanup EXIT
fi

# Log the command
cmd_log="$PWD/day_cmd.log"
cmddt=$(date --iso-8601="seconds")
echo "SMK> D:$cmddt / U:$USER / PWD:$PWD / CMD: (${snakecmd[*]})" >> "$cmd_log"

_day_write_pipeline_snapshot() {
    local _state="$1"
    local _details_flag="${2:-}"
    python -m daylily_omics_analysis.pipeline_reports \
        --analysis-root "$PWD" \
        --workflow-root "$PWD/workflow" \
        --output-dir "$PWD" \
        --genome-build "$DAY_GENOME_BUILD" \
        --state "$_state" \
        --command "${snakecmd[*]}" \
        $_details_flag
}

_day_capture_preflight_output() {
    local _kind="$1"
    local _action="$2"
    local _output="$3"
    local _partial="${_output}.partial.$$"
    if ! "${_dayoa_preflight_base[@]}" --dry-run "$_action" > "$_partial"; then
        if [[ -s "$_partial" ]]; then
            cat "$_partial" 1>&2
        fi
        rm -f "$_partial"
        colr "ERROR: dy-r $_kind preflight failed; formal Snakemake execution was not started." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        return 2
    fi
    if [[ ! -s "$_partial" ]]; then
        rm -f "$_partial"
        colr "ERROR: dy-r $_kind preflight produced no output." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
        return 2
    fi
    mv "$_partial" "$_output"
}

_day_render_graph() {
    local _kind="$1"
    local _raw="$2"
    local _mmd="$3"
    local _png="$4"
    python -m daylily_omics_analysis.ursa_artifacts render-graph \
        --kind "$_kind" \
        --dot "$_raw" \
        --mermaid "$_mmd" \
        --png "$_png"
}

_day_run_requested_preflights() {
    local _arg
    local _summary=""
    local _manifest_filegraph=""
    local _filegraph_raw=""
    local _rulegraph_raw=""
    local _dag_raw=""
    local _manifest_cmd
    _dayoa_preflight_base=()
    _dayoa_graph_artifacts=()
    for _arg in "${snakecmd[@]}"; do
        case "$_arg" in
            -n|--dry-run|--dryrun) continue ;;
        esac
        _dayoa_preflight_base+=("$_arg")
    done

    if [[ "$_produce_ursa_manifest" == "true" ]]; then
        mkdir -p .snakemake
        _summary=".snakemake/ursa_summary_${timestamp}.tsv"
        _day_capture_preflight_output "Ursa summary" "--summary" "$_summary" || return $?
    fi
    if [[ "$_produce_filegraph" == "true" || "$_produce_rulegraph" == "true" || "$_produce_dag" == "true" ]]; then
        mkdir -p dags
    fi
    if [[ "$_produce_filegraph" == "true" ]]; then
        _filegraph_raw="dags/filegraph_${timestamp}.txt"
        _day_capture_preflight_output "filegraph" "--filegraph" "$_filegraph_raw" || return $?
        _manifest_filegraph="$_filegraph_raw"
    elif [[ "$_produce_ursa_manifest" == "true" ]]; then
        _manifest_filegraph=".snakemake/ursa_filegraph_${timestamp}.dot"
        _day_capture_preflight_output "Ursa producer filegraph" "--filegraph" "$_manifest_filegraph" || return $?
    fi
    if [[ "$_produce_rulegraph" == "true" ]]; then
        _rulegraph_raw="dags/rulegraph_${timestamp}.txt"
        _day_capture_preflight_output "rulegraph" "--rulegraph" "$_rulegraph_raw" || return $?
    fi
    if [[ "$_produce_dag" == "true" ]]; then
        _dag_raw="dags/dag_${timestamp}.txt"
        _day_capture_preflight_output "DAG" "--dag" "$_dag_raw" || return $?
    fi

    if [[ -n "$_filegraph_raw" ]]; then
        _day_render_graph \
            filegraph \
            "$_filegraph_raw" \
            "dags/filegraph_${timestamp}.mmd" \
            "dags/filegraph_${timestamp}.png" || return $?
        _dayoa_graph_artifacts+=(
            "$_filegraph_raw"
            "dags/filegraph_${timestamp}.mmd"
            "dags/filegraph_${timestamp}.png"
        )
    fi
    if [[ -n "$_rulegraph_raw" ]]; then
        _day_render_graph \
            rulegraph \
            "$_rulegraph_raw" \
            "dags/rulegraph_${timestamp}.mmd" \
            "dags/rulegraph_${timestamp}.png" || return $?
        _dayoa_graph_artifacts+=(
            "$_rulegraph_raw"
            "dags/rulegraph_${timestamp}.mmd"
            "dags/rulegraph_${timestamp}.png"
        )
    fi
    if [[ -n "$_dag_raw" ]]; then
        _day_render_graph \
            dag \
            "$_dag_raw" \
            "dags/dag_${timestamp}.mmd" \
            "dags/dag_${timestamp}.png" || return $?
        _dayoa_graph_artifacts+=(
            "$_dag_raw"
            "dags/dag_${timestamp}.mmd"
            "dags/dag_${timestamp}.png"
        )
    fi

    if [[ "$_produce_ursa_manifest" == "true" ]]; then
        _dayoa_ursa_manifest="$PWD/ursa_artifacts_to_import_${timestamp}.log"
        _manifest_cmd=(
            python -m daylily_omics_analysis.ursa_artifacts build-manifest
            --summary "$_summary"
            --analysis-root "$PWD"
            --workflow-root "$PWD/workflow"
            --filegraph "$_manifest_filegraph"
            --output "$_dayoa_ursa_manifest"
        )
        for _arg in "${_ursa_manifest_excludes[@]}"; do
            _manifest_cmd+=(--exclude "$_arg")
        done
        for _arg in "${_dayoa_graph_artifacts[@]}"; do
            _manifest_cmd+=(--graph "$_arg")
        done
        if ! "${_manifest_cmd[@]}"; then
            rm -f "$_summary"
            if [[ "$_manifest_filegraph" == .snakemake/ursa_filegraph_* ]]; then
                rm -f "$_manifest_filegraph"
            fi
            colr "ERROR: dy-r Ursa manifest preflight failed; formal Snakemake execution was not started." "$DY_WT0" "$DY_WB0" "$DY_WS1" 1>&2
            return 2
        fi
        rm -f "$_summary"
        if [[ "$_manifest_filegraph" == .snakemake/ursa_filegraph_* ]]; then
            rm -f "$_manifest_filegraph"
        fi
        _dayoa_snapshot_native_logs
    fi
}

if [[ "$_produces_preflight_artifacts" == "true" ]]; then
    _day_run_requested_preflights || exit $?
fi

# Run snakemake command
colr "Executing: ${snakecmd[*]}"  "$DY_IT0" "$DY_IB0" "$DY_IS1"  1>&2
if [[ "$_is_dry_run" == "true" ]]; then
    "${snakecmd[@]}"
    ret_code=$?
else
    _day_write_pipeline_snapshot planned --write-details
    report_ret_code=$?
    if [[ "$report_ret_code" -ne 0 ]]; then
        exit "$report_ret_code"
    fi
    _day_write_pipeline_snapshot checkpoint
    report_ret_code=$?
    if [[ "$report_ret_code" -ne 0 ]]; then
        exit "$report_ret_code"
    fi
    checkpoint_failure_file=".dayoa_pipeline_report_monitor.failed"
    rm -f "$checkpoint_failure_file"
    (
        "${snakecmd[@]}" &
        snakemake_pid=$!
        (
            while kill -0 "$snakemake_pid" 2>/dev/null; do
                sleep "${DAYOA_PIPELINE_REPORT_INTERVAL_SECONDS:-900}"
                if kill -0 "$snakemake_pid" 2>/dev/null; then
                    _day_write_pipeline_snapshot checkpoint || {
                        echo "checkpoint workflow diagram generation failed" > "$checkpoint_failure_file"
                        exit 2
                    }
                fi
            done
        ) &
        checkpoint_pid=$!
        wait "$snakemake_pid"
        workflow_ret_code=$?
        kill "$checkpoint_pid" 2>/dev/null || true
        wait "$checkpoint_pid" 2>/dev/null || true
        if [[ -s "$checkpoint_failure_file" ]]; then
            cat "$checkpoint_failure_file" 1>&2
            exit 2
        fi
        if [[ "$workflow_ret_code" -eq 0 ]]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S')" >> daylily.successful_run
            bash bin/util/benchmarks/collect_day_benchmark_data.sh "$DAY_GENOME_BUILD" > /dev/null 2>&1
        fi
        exit "$workflow_ret_code"
    )
    ret_code=$?
    if [[ "$ret_code" -ne 0 ]]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S')" >> daylily.failed_run
    fi
    if [[ "$ret_code" -eq 0 ]]; then
        _day_write_pipeline_snapshot final_success
        ret_code=$?
    else
        _day_write_pipeline_snapshot final_failed
        report_ret_code=$?
        if [[ "$report_ret_code" -ne 0 ]]; then
            ret_code="$report_ret_code"
        fi
    fi
fi

if [[ -n "$_dayoa_ursa_manifest" ]]; then
    _dayoa_finalize_ursa_manifest "$ret_code"
    manifest_ret_code=$?
    if [[ "$ret_code" -eq 0 && "$manifest_ret_code" -ne 0 ]]; then
        ret_code="$manifest_ret_code"
    fi
fi

colr "RETURN CODE: $ret_code" "$DY_IB0" "$DY_IT0" "$DY_IS0" 1>&2
exit $ret_code
