#!/usr/bin/env bash

export SNAKEMAKE_SINGULARITY_CMD="apptainer"

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

timestamp=$(date +%Y%m%d%H%M%S);

CONFIG_FILE=~/.config/daylily/daylily_cli_global.yaml
export TMPDIR=$(yq -r '.daylily.sentieon_tmpdir' "$CONFIG_FILE")
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

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
_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, -
}

for _arg in "$@"; 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
done

# 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" "$@")

snakecmd="${snakecmd_init[@]//\-\-keep-temp/\-\-notemp}"

# This ensures the snakedir is unlocked after a crash or successful exit 0
trap "(snakemake --unlock --profile $DAY_PROFILE_DIR  &>> ./unlock_fails.log & ) & " EXIT

# 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
}

# 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

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