#!/usr/bin/bash

# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
#
#    NAME
#        sql-scheduler - SQL scheduler service
#
#    DESCRIPTION
#        Starts, stops and restarts a SQL scheduler service
#
#    NOTES
#
#    CHANGE LOG
#        MODIFIED    VERSION    (MM/DD/YY)
#        admuro      1.0.0      02/05/25 - Script creation
#
#    TODO:
#
# chkconfig: 35 99 98
# pidfile: /var/run/sql-scheduler/pid
# description: SQL Scheduler Service

pid_file_home="${SQL_SCHEDULER_PID_FILE_HOME:-/var/run/sql-scheduler}"
pid_file_path="${SQL_SCHEDULER_PID_FILE_PATH:-$pid_file_home/pid}"
log_file="${SQL_SCHEDULER_LOG_FILE:-/var/log/sql-schedule.logs}"

if [ ! -d "$pid_file_home" ]; then
    mkdir -p "$pid_file_home"
fi

function _out_msg() {
    local severity="$1"
    local message="$2"
    local timestamp

    timestamp="$(date +%Y-%m-%dT%T.%3NZ)"
    if [ "$severity" = "ERROR" ]; then
        printf "\a%s%s\n" "$timestamp ERR: " "$message" >>"$log_file" &
    else
        printf "\a%s%s\n" "$timestamp INF: " "$message" >>"$log_file" &
    fi
    printf "\a%s%s\n" "$message" &
}

function _is_sqlcl_daemon_pid() {
    local pid="$1"
    local cmdline

    case "$pid" in
        ''|*[!0-9]*)
            return 1
            ;;
    esac

    cmdline="$(ps -p "$pid" -o args= 2>/dev/null || true)"
    [ -n "$cmdline" ] && [[ "$cmdline" == *oracle.dbtools.raptor.scriptrunner.cmdline.SqlCli* ]] \
        && [[ "$cmdline" == *" -daemon"* ]]
}

function _sqlcl_pid_file_for_user() {
    local user="$1"
    local user_home

    user_home="$(getent passwd "$user" | cut -d':' -f 6)"
    printf '%s\n' "$user_home/.dbtools/schedules/pid"
}

function _scheduler_group_users() {
    getent group sql-scheduler | cut -d':' -f 4 | tr ',' '\n'
}

function _resolve_sqlcl_daemon_pid_for_user() {
    local user="$1"
    local pid_file_path_for_user
    local pid

    pid_file_path_for_user="$(_sqlcl_pid_file_for_user "$user")"
    if [ -f "$pid_file_path_for_user" ]; then
        pid="$(tr -d '[:space:]' <"$pid_file_path_for_user")"
        if [ -n "$pid" ] && _is_sqlcl_daemon_pid "$pid"; then
            printf '%s\n' "$pid"
            return 0
        fi
    fi

    pid="$(
        ps -u "$user" -o pid= -o args= 2>/dev/null \
            | awk '$0 ~ /oracle.dbtools.raptor.scriptrunner.cmdline.SqlCli/ && $0 ~ / -daemon/ {print $1; exit}'
    )"
    if [ -n "$pid" ] && _is_sqlcl_daemon_pid "$pid"; then
        printf '%s\n' "$pid"
        return 0
    fi

    return 1
}

function _running() {
    local pid
    local user

    if [ -f "$pid_file_path" ]; then
        pid="$(tr -d '[:space:]' <"$pid_file_path")"
        if _is_sqlcl_daemon_pid "$pid"; then
            echo "$pid"
            return 0
        fi
        rm -f "$pid_file_path"
    fi

    while IFS= read -r user; do
        [ -n "$user" ] || continue
        if pid="$(_resolve_sqlcl_daemon_pid_for_user "$user")"; then
            echo "$pid"
            return 0
        fi
    done <<-_SCRIPT
$(_scheduler_group_users)
_SCRIPT

    echo 0
}

function _start() {
    local daemon_pid
    local exit_code
    local user
    local start_failed=0
    local started_pid=''

    touch "$log_file"
    chown root:sql-scheduler "$log_file"
    chmod 660 "$log_file"

    _out_msg "INFO" "Starting the SQLcl Scheduler Daemon."
    while IFS= read -r user; do
        [ -n "$user" ] || continue
        daemon_pid=''

        if daemon_pid="$(_resolve_sqlcl_daemon_pid_for_user "$user")"; then
            _out_msg "INFO" "The SQLcl Scheduler Daemon is already running for user ${user}."
            [ -z "$started_pid" ] && started_pid="$daemon_pid"
            continue
        fi

        _out_msg "INFO" "Starting the SQLcl Scheduler Daemon for user ${user}."
        sudo -iu "$user" <<-_SCRIPT
            sql -daemon start 2>&1 | tee -a "$log_file"
_SCRIPT
        exit_code="$?"
        if [ "$exit_code" -gt 0 ]; then
            start_failed=1
            _out_msg "ERROR" "The SQLcl Scheduler Daemon did not start correctly for user ${user}."
            continue
        fi

        for _ in 1 2 3 4 5; do
            if daemon_pid="$(_resolve_sqlcl_daemon_pid_for_user "$user")"; then
                break
            fi
            sleep 1
        done

        if [ -n "$daemon_pid" ]; then
            [ -z "$started_pid" ] && started_pid="$daemon_pid"
            _out_msg "INFO" "The SQLcl Scheduler Daemon started correctly for user ${user}."
        else
            start_failed=1
            _out_msg "ERROR" "The SQLcl Scheduler Daemon did not produce a valid tracked PID for user ${user}."
        fi
    done <<-_SCRIPT
$(_scheduler_group_users)
_SCRIPT

    if [ "$start_failed" -gt 0 ]; then
        rm -f "$pid_file_path"
        _out_msg "ERROR" "The SQLcl Scheduler Daemon did not start correctly."
        exit 1
    fi

    if [ -n "$started_pid" ]; then
        printf '%s\n' "$started_pid" >"$pid_file_path"
        _out_msg "INFO" "The SQLcl Scheduler Daemon has started correctly."
    else
        _out_msg "ERROR" "The SQLcl Scheduler Daemon did not produce a valid tracked PID."
        exit 1
    fi
}

function _stop() {
    local exit_code
    local user
    local stop_failed=0
    local stopped_any=0

    _out_msg "INFO" "Stopping the SQLcl Scheduler Daemon."
    while IFS= read -r user; do
        [ -n "$user" ] || continue

        if ! _resolve_sqlcl_daemon_pid_for_user "$user" >/dev/null; then
            continue
        fi

        _out_msg "INFO" "Stopping SQLcl Scheduler Daemon for user ${user}."
        sudo -iu "$user" <<-_SCRIPT
            sql -daemon stop 2>&1 | tee -a "$log_file"
_SCRIPT
        exit_code="$?"
        if [ "$exit_code" -gt 0 ]; then
            stop_failed=1
            _out_msg "ERROR" "The SQLcl Scheduler Daemon did not stop correctly for user ${user}."
        else
            stopped_any=1
        fi
    done <<-_SCRIPT
$(_scheduler_group_users)
_SCRIPT

    rm -f "$pid_file_path"

    if [ "$stop_failed" -gt 0 ]; then
        _out_msg "ERROR" "The SQLcl Scheduler Daemon did not stop correctly."
    elif [ "$stopped_any" -gt 0 ]; then
        _out_msg "INFO" "The SQLcl Scheduler Daemon has stopped correctly."
    else
        _out_msg "INFO" "No running SQLcl Scheduler Daemon was found."
    fi
}
case "${1}" in
    start)
        _start
        ;;
    stop)
        _stop
        ;;
    restart)
        _stop
        _start
        ;;
esac
