#!/usr/bin/env bash
# Chrony service provision
# Tool for provision chrony service
#
# Copyright (C) 2025 Mukhin Michael <domfrost78@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# shellcheck disable=SC2034
# shellcheck disable=SC1091
# shellcheck disable=SC2086
# shellcheck disable=SC2317
# shellcheck disable=SC3037

set -euo pipefail

. shell-getopt
. shell-ini-config

show_usage() {
    cat <<EOF
Usage: $PROG_NAME [OPTIONS]

Tool for managing the chrony service.

Options:
    -h, --help            Show this help message and exit
    -v, --version         Show version information and exit
    -u, --undeploy        Undeploy the chrony service
    -d, --deploy          Deploy the chrony service
    -r, --restore         Restore the chrony service configuration from backup
    -b, --backup          Create a backup of the chrony service configuration
    -s, --status          Show the current status of the chrony service
        --start           Start the chrony service
        --stop            Stop the chrony service
        --configure       Configure the chrony service
EOF
    exit 0
}


PROG_NAME="${0##*/}"
VERSION="0.1"
MODE="provision"
GLOBAL_EXIT=0
input_json=
entryfile=/usr/share/alterator/service/service-chrony.service

OPTIONS_LIST="help,
              version,
              undeploy,
              deploy,
              restore,
              backup,
              status,
              start,
              stop,
              configure"

OPTIONS_SHORT_LIST="h,v,u,d,b,r,s"

TEMP=$(getopt -n "$PROG_NAME" -o "$OPTIONS_SHORT_LIST" -l "$OPTIONS_LIST" -- "$@")
eval set -- "$TEMP"

while :; do
    case "$1" in
        -h|--help)
            show_usage
            ;;
        -v|--version)
            show_version
            ;;
        -u|--undeploy)
            MODE="undeploy"
            ;;
        -d|--deploy)
            MODE="deploy"
            ;;
        -r|--restore)
            MODE="restore"
            ;;
        -b|--backup)
            MODE="backup"
            ;;
        -s|--status)
            MODE="status"
            ;;
        --start)
            MODE="start"
            ;;
        --stop)
            MODE="stop"
            ;;
        --configure)
            MODE="configure"
            ;;
        --) shift; break
            ;;
        *) fatal "Unrecognized option: $1"
            ;;
    esac
    shift
done


backup_config() {
    local config_file="$1"
    local type="$2"
    local retval=0
    
    local backup_file=

    backup_file="/var/lib/alterator/service/service-chrony/backups/$(basename $config_file).$type"
    if [ -f "$backup_file" ]; then
        echo "Backup file $backup_file already exists, skipping backup."
    fi
    if [ -f "$config_file" ]; then
        cp -u "$config_file" "$backup_file" || retval=1
    else
        echo "File $config_file not found, skipping backup."
    fi

    return $retval
}

read_stdin() {
	local input_json=
	local retval=0

	if [ -t 0 ]; then
		echo "Reading from stdin..."
		echo "Please provide JSON input:"
		retval=1
	else
		while read -r line; do
			input_json="${input_json}$line"
		done
	fi

	echo "$input_json"
	return $retval
}

parse_json() {
    local json_struct="$1"
    local param_name="$2"
    local retval=0

    local param_value=
    param_value="$(echo "$json_struct" | jq -r ".$param_name")"
    if [ -z "$param_value" ]; then
        false
    else
        echo "$param_value"
    fi

    return 0
}


set_ntp_entry(){
    local type="$1"
    local input_json="$2"
    local json_path="$3"
    local flag="${4:-0}"
    local retval=0

    local ntp_array ntp_json
    local domain bursts minpoll maxpoll no_select prefer offline require trust maxsources
    local ntp_line last_line

    ntp_array=$(echo "$input_json" | jq -c "$json_path") || retval=1

    echo "$ntp_array" | jq -c 'if type=="array" then .[] else . end' | while read -r ntp_json; do
        case "$type" in
            server) domain=$(echo "$ntp_json" | jq -r '.serverDomainName') ;;
            pool) domain=$(echo "$ntp_json" | jq -r '.poolDomainName') ;;
            default_pool) domain="pool.ntp.org" ;;
        esac
        bursts=$(echo "$ntp_json" | jq -r '.bursts | if . != null then (keys_unsorted[0]) else empty end')
        minpoll=$(echo "$ntp_json" | jq -r '.minpoll // empty')
        maxpoll=$(echo "$ntp_json" | jq -r '.maxpoll // empty')
        no_select=$(echo "$ntp_json" | jq -r '.noSelect // empty')
        prefer=$(echo "$ntp_json" | jq -r '.prefer // empty')
        offline=$(echo "$ntp_json" | jq -r '.offline | if . != null then (keys_unsorted[0]) else empty end')
        require=$(echo "$ntp_json" | jq -r '.require // empty')
        trust=$(echo "$ntp_json" | jq -r '.trust // empty')
        maxsources=$(echo "$ntp_json" | jq -r '.maxsources // empty')

        if [ "$type" = "default_pool" ]; then
            ntp_line="pool $domain"
        else
            ntp_line="$type"
            [ -n "$domain" ] && ntp_line="$ntp_line $domain"
        fi

        [ -n "$bursts" ] && ntp_line="$ntp_line $bursts"
        [ -n "$minpoll" ] && ntp_line="$ntp_line minpoll $minpoll"
        [ -n "$maxpoll" ] && ntp_line="$ntp_line maxpoll $maxpoll"
        [ "$no_select" = "true" ] && ntp_line="$ntp_line noselect"
        [ "$prefer"    = "true" ] && ntp_line="$ntp_line prefer"
        [ "$require" = "true" ] && ntp_line="$ntp_line require"
        [ "$trust"   = "true" ] && ntp_line="$ntp_line trust"
        [ -n "$offline" ] && ntp_line="$ntp_line $offline"
        if [ "$type" != "server" ] && [ -n "$maxsources" ]; then
            ntp_line="$ntp_line maxsources $maxsources"
        fi

        if [ "$type" = "default_pool" ]; then
            if [ "$flag" -eq 1 ]; then
                sed -i "s|^\(#*\)pool pool\.ntp\.org.*\$|#${ntp_line}|" /etc/chrony.conf
            else
                sed -i "s|^\(#*\)pool pool\.ntp\.org.*\$|\1$ntp_line|" /etc/chrony.conf
            fi
        else
            if grep -q "^$type $domain" /etc/chrony.conf; then
                sed -i "s|^$type $domain.*|$ntp_line|" /etc/chrony.conf
            elif grep -q "^$type " /etc/chrony.conf; then
                last_line=$(grep -n "^$type " /etc/chrony.conf | tail -n 1 | cut -d: -f1)
                sed -i "${last_line}a $ntp_line" /etc/chrony.conf
            else
                sed -i "8i $ntp_line" /etc/chrony.conf
            fi
        fi
        echo "$ntp_line"
    done

    return $retval
}

call_deploy() {
    local retval=0
    local input_json=
    local flag=0
    input_json="$(read_stdin)"

    echo "Data is received from stdin"

    backup_config /etc/chrony.conf "original" || retval=1

    echo "$input_json" > /var/lib/alterator/service/service-chrony/backups/deployment-config.json || retval=1

    keys=$(echo "$input_json" | jq -r 'keys[]')
    for key in $keys; do
        case "$key" in
            disableDefaultPoll)
                local default_pool_value=
                default_pool_value="$(parse_json "$input_json" "$key")"
                if [ -n "$default_pool_value" ] && [ "$default_pool_value" != "null" ] && [ "$default_pool_value" = "true" ]; then
                    sed -i '/^pool pool\.ntp\.org/ s/^/#/' /etc/chrony.conf
                    echo "Default pool of NTP servers is disabled"
                    flag=1
                fi  
                ;;
            makestep)
                local makestep_value=
                makestep_value="$(parse_json "$input_json" "$key")"
                if [ -n "$makestep_value" ] && [ "$makestep_value" != "null" ]; then
                    sed -i "s/^makestep .*/makestep ${makestep_value}/" /etc/chrony.conf 
                    echo "Makestep is set to ${makestep_value}"
                fi
                ;;
            rtcSync)
                local rtc_value=
                rtc_value="$(parse_json "$input_json" "$key")"
                if [ -n "$rtc_value" ] && [ "$rtc_value" = "false" ]
                then
                    sed -i '/^\s*rtcsync\s*$/d' /etc/chrony.conf
                    echo "RTC sync is canseled"
                else echo "RTC sync is set"
                fi
                ;;
            ntpServersSettings)
                set_ntp_entry "server" "$input_json" ".ntpServersSettings" || retval=1
                ;;
            ntpPoolsSettings)
                set_ntp_entry "pool" "$input_json" ".ntpPoolsSettings" || retval=1
                ;;
            ntpDefaultPool)
                set_ntp_entry "default_pool" "$input_json" ".ntpDefaultPool" || retval=1
                ;;
            *)
            
                false
                ;;
        esac
    done

    rm -f /var/lib/alterator/service/service-chrony/undeploy_success

    if [ $retval -eq 0 ]; then
        echo "Service is ready!"
    else
        echo "An error occurred while processing the input data."
        retval=1
    fi
    return $retval
}

call_start() {
    local retval=0
    systemctl enable --now chronyd.service || retval=1
    if [ $retval -eq 0 ]; then
        echo "Service chronyd started successfully."
    else
        echo "Failed to start service chronyd."
    fi

    return $retval
}

call_stop(){
    local retval=0
    systemctl disable --now  chronyd.service || retval=1
    if [ $retval -eq 0 ]; then
        echo "Service chronyd stoped successfully."
    else
        echo "Failed to stop service chronyd."
    fi

    return $retval
}

call_undeploy(){
    local retval=0
    local chrony_dir="/var/lib/alterator/service/service-chrony/"
    local default_config_json
    local real_config_json
    default_config_json=$(parse_conf_file /var/lib/alterator/service/service-chrony/default-chrony.conf)
    real_config_json=$(parse_conf_file /etc/chrony.conf)
    tmp1=$(mktemp)
    tmp2=$(mktemp)
    local input_json=
    input_json="$(read_stdin)"
    local reset_to_defaults save_current_config

    echo "$default_config_json" | jq -S . >"$tmp1"
    echo "$real_config_json" | jq -S . >"$tmp2"
    
    keys=$(echo "$input_json" | jq -r 'keys[]')
    for key in $keys; do
        case "$key" in
            resetToDefaults)
                reset_to_defaults="$(parse_json "$input_json" "$key")"
                ;;
            saveCurrentConfig)
                save_current_config="$(parse_json "$input_json" "$key")"
                ;;
            *)
                echo "Unrecognized key: $key"
                retval=1
                ;;
        esac
    done

    if diff "$tmp1" "$tmp2" >/dev/null; then
        echo "The current configuration is the same as the default configuration."
        call_stop
    else
        echo "Undeploying in progress..."
        if [ $save_current_config = true ]; then
            backup_config /etc/chrony.conf "before_undeploy" || retval=1
            echo "Creating backup of the current configuration file"
        fi
        if [ -f "$chrony_dir/backups/chrony.conf.original" ]; then
            rm -f "$chrony_dir/backups/deployment-config.json"
            rm -f "$chrony_dir/backups/configuring-config.json"
            if [ $reset_to_defaults = true ]; then
                mv -f "$chrony_dir/backups/chrony.conf.original" /etc/chrony.conf
                echo "Restored configuration file from backup"
            fi
        elif [ -f "$chrony_dir/backups/chrony.conf.before_configure" ]; then
            rm -f "$chrony_dir/backups/deployment-config.json"
            rm -f "$chrony_dir/backups/configuring-config.json"
            if [ $reset_to_defaults = true ]; then
                mv -f "$chrony_dir/backups/chrony.conf.before_configure" /etc/chrony.conf
                echo "Restored configuration file from backup"
            fi
        else
            if [ $reset_to_defaults = true ]; then
                cp -f "$chrony_dir/default-chrony.conf" /etc/chrony.conf
                echo "Restored default configuration file"
            fi
        fi
        chmod 644 /etc/chrony.conf
        call_stop
        touch "$chrony_dir/undeploy_success"  
    fi
    return $retval
}

call_status() {
    local deployment_config_file="/var/lib/alterator/service/service-chrony/backups/deployment-config.json"
    local configuring_config_file="/var/lib/alterator/service/service-chrony/backups/configuring-config.json"
    local conf="/etc/chrony.conf"
    local status_output=
    local tmp_file=
    tmp_file=$(mktemp)
    
    status_output=$(parse_conf_file /etc/chrony.conf)

    if [ -f "/var/lib/alterator/service/service-chrony/undeploy_success" ] || [ ! -f "$conf" ]; then
        exit 0
    else
        printf '%s' "$status_output" | jq '.deployed=true' >"$tmp_file"
        status_output="$(cat $tmp_file)"
        if systemctl is-active --quiet chrony.service; then
            printf '%s' "$status_output" | jq '.started=true' >"$tmp_file"
            status_output="$(cat $tmp_file)"
        else
            printf '%s' "$status_output" | jq '.started=false' >"$tmp_file"
            status_output="$(cat $tmp_file)"
        fi
    fi

    echo "$status_output"

    exit 0
}

make_ntp_entry() {
    local type="$1"
    local domain="$2"
    local bursts="$3"
    local minpoll="$4"
    local maxpoll="$5"
    local maxsources="$6"
    local noselect="$7"
    local prefer="$8"
    local offline="$9"
    local require="${10}"
    local trust="${11}"

    jq -n \
      --arg entryType "$type" \
      --arg domainName "$domain" \
      --arg burstsValue "$bursts" \
      --arg minpollValue "$minpoll" \
      --arg maxpollValue "$maxpoll" \
      --arg maxsourcesValue "$maxsources" \
      --arg noselectFlag "$noselect" \
      --arg preferFlag "$prefer" \
      --arg offlineValue "$offline" \
      --arg requireFlag "$require" \
      --arg trustFlag "$trust" '
      (if $entryType == "server" then
         {serverDomainName: $domainName}
        elif $entryType == "pool" then
         (if $domainName != "pool.ntp.org" then
            {poolDomainName: $domainName}
          else
            {}
          end)
        else {} end)
      + (if $burstsValue != "" then {bursts: {($burstsValue): {}}} else {} end)
      + (if $minpollValue != "" then {minpoll: ($minpollValue|tonumber)} else {} end)
      + (if $maxpollValue != "" then {maxpoll: ($maxpollValue|tonumber)} else {} end)
      + (if $maxsourcesValue != "" then {maxsources: ($maxsourcesValue|tonumber)} else {} end)
      + (if $noselectFlag == "true" then {noSelect: true} else {} end)
      + (if $preferFlag == "true" then {prefer: true} else {} end)
      + (if ($offlineValue == "offline" or $offlineValue == "auto_offline") then {offline: {($offlineValue): {}}} else {} end)
      + (if $requireFlag == "true" then {require: true} else {} end)
      + (if $trustFlag == "true" then {trust: true} else {} end)'
}

parse_conf_file(){
    local conf_file="$1"
    local line
    local makestep_value=""
    local rtc_sync=false
    local disable_default_poll=false
    local servers=""
    local pools=""
    local subnets=""
    local local_stratum=""
    local default_pool=null
    while IFS= read -r line || [ -n "$line" ]; do
        case "$line" in
            *"#pool pool.ntp.org"*)
                disable_default_poll=true
            ;;
        esac
        case "$line" in
            *"rtcsync"*)
            case "$line" in
                *"#"*rtcsync*) rtc_sync=false ;;
                *rtcsync*) rtc_sync=true ;;
            esac
            continue
            ;;
        esac
        case "$line" in
            ""|"#"*) continue ;;
        esac
        case "$line" in
            makestep*)
                makestep_value=$(printf '%s\n' "$line" | sed -n 's/^[ 	]*makestep[ 	]\+//p')
                continue
            ;;
        esac
        case "$line" in
            *"local stratum"*) 
                local_stratum=$(printf '%s\n' "$line" | sed -n 's/^.*local[ 	]\+stratum[ 	]\+\([0-9]\+\).*$/\1/p' )
            continue
            ;;
        esac
        case "$line" in
            allow*)
                ip=$(printf '%s' "$line" | awk '{print $2}')
                case "$ip" in
                    [0-9]*.[0-9]*.[0-9]*.[0-9]*/[0-9][0-9] | \
                    [0-9]*.[0-9]*.[0-9]*.[0-9]*/[0-9])
                        if [ -n "$subnets" ]; then
                            subnets="${subnets}
${ip}"
                        else
                            subnets="$ip"
                        fi
                        ;;
                esac
                continue
                ;;
        esac
        case "$line" in
            server*|pool*)
            local type
            type="$(printf '%s\n' "$line" | awk '{print $1}')"
            local domain
            domain="$(printf '%s\n' "$line" | awk '{print $2}')"
            local key=""
            local bursts=""
            local maxsources=""
            local minpoll=""
            local maxpoll=""
            local noselect=""
            local prefer=""
            local offline=""
            local require=""
            local trust=""
            local num

            set -- $line
            shift 2
            for word in "$@"; do
                case "$word" in
                    iburst|burst) bursts="$word" ;;
                    offline|auto_offline) offline="$word" ;;
                    noselect) noselect="true" ;;
                    prefer) prefer="true" ;;
                    require) require="true" ;;
                    trust) trust="true" ;;
                    minpoll|maxpoll|maxsources) key="$word" ;;
                    *[0-9]*)
                        num=$word
                        case "$key" in
                            minpoll)
                              if [ "$num" -ge -7 ] && [ "$num" -le 24 ] && [ -z "$minpoll" ]; then
                                minpoll=$num
                                key=""
                              fi 
                              ;;
                            maxpoll)
                              if [ "$num" -ge -7 ] && [ "$num" -le 24 ] && [ -z "$maxpoll" ]; then
                                maxpoll=$num
                                key=""
                              fi ;;
                            maxsources)
                              if [ "$num" -ge 1 ] && [ "$num" -le 16 ] && [ -z "$maxsources" ]; then
                                maxsources=$num 
                                key=""
                              fi 
                              ;;
                        esac
                        ;;
                    *)
                        ;;
                esac
            done
            ntp_entry=$(make_ntp_entry "$type" "$domain" "$bursts" "$minpoll" "$maxpoll" "$maxsources" "$noselect" "$prefer" "$offline" "$require" "$trust")
            if [ "$type" = "server" ]; then
                [ -n "$servers" ] && servers="$(printf '%s\n%s' "$servers" "$ntp_entry")" || servers="$ntp_entry"
            elif [ "$type" = "pool" ]; then
                if [ "$domain" = "pool.ntp.org" ]; then
                    default_pool=$ntp_entry
                else
                    [ -n "$pools" ] && pools="$(printf '%s\n%s' "$pools" "$ntp_entry")" || pools="$ntp_entry"
                fi
            fi
        esac
    done < "$conf_file"

    local result
    result=$(jq -n \
        --arg makestep "$makestep_value" \
        --arg ls "$local_stratum" \
        --argjson subnets "$(
            printf '%s\n' "$subnets" \
            | jq -R 'select(length>0)' \
            | jq -s '.'
        )" \
        --argjson rtcSync "$rtc_sync" \
        --argjson servers "$(printf '%s\n' $servers | jq -s '.')" \
        --argjson pools "$(printf '%s\n' $pools | jq -s '.')" \
        --argjson defaultPool "$default_pool" \
        --argjson disableDefaultPoll "$disable_default_poll" '
        {
          rtcSync: $rtcSync
        }
        + (if ($servers | length) > 0 then {ntpServersSettings: $servers} else {} end)
        + (if ($pools   | length) > 0 then {ntpPoolsSettings:   $pools}   else {} end)
        + (if $makestep != "" then {makestep: $makestep} else {} end)
        + (if $defaultPool != null and ($defaultPool | length > 0)
           then {ntpDefaultPool: $defaultPool}
           else {} end)
        + (
            ($ls | length > 0 or ($subnets | length > 0))
            | if . then {
                clientsSettings:
                  ({} +
                   (if $ls | length > 0 then {localStratum: ($ls | tonumber)} else {} end) +
                   (if $subnets | length > 0 then {subnetIpAddresses: $subnets} else {} end)
                  )
              } else {} end
          )
        + (if $disableDefaultPoll then {disableDefaultPoll: true} else {} end)
    ')
    echo "$result"
}

call_backup(){
    local retval=0
    local input_json=
    
    input_json="$(read_stdin)"

    keys=$(echo "$input_json" | jq -r 'keys[]')
    for key in $keys; do
        case "$key" in
            backupName)
                local backup_name=
                backup_name="$(parse_json "$input_json" "$key")"
                if [ -z "$backup_name" ]; then
                    echo "Backup name is empty, exiting."
                    retval=1
                else backup_config "/etc/chrony.conf" "$backup_name" || retval=1
                    echo "Backup of the configuration file created with name: $backup_name"
                fi
                ;;
            *)
                echo "Unrecognized key: $key"
                retval=1
                ;;
        esac
    done

    return $retval
}

call_restore(){
    local retval=0
    local input_json=
    local backup_dir="/var/lib/alterator/service/service-chrony/backups"
    input_json="$(read_stdin)"

    keys=$(echo "$input_json" | jq -r 'keys[]')
    for key in $keys; do
        case "$key" in
            backupName)
                local backup_name=
                backup_name="$(parse_json "$input_json" "$key")"
                if [ -z "$backup_name" ]; then
                    echo "Backup name is empty, exiting."
                    retval=1
                elif [ ! -f "/var/lib/alterator/service/service-chrony/backups/chrony.conf.$backup_name" ]; then
                    echo "Backup file /var/lib/alterator/service/service-chrony/backups/chrony.conf.$backup_name does not exist."
                    retval=1
                else
                    cp -f "$backup_dir/chrony.conf.$backup_name" /etc/chrony.conf
                    chmod 644 /etc/chrony.conf
                    echo "Restored original configuration file from backup."
                fi

                ;;
            *)
                echo "Unrecognized key: $key"
                retval=1
                ;;
        esac
    done

    return $retval
}

call_configure(){
    local retval=0
    local input_json=
    local flag=0
    input_json="$(read_stdin)"
    
    echo "Data is received from stdin"

    if [ ! -f "/var/lib/alterator/service/service-chrony/backups/chrony.conf.before_configure" ]; then
        cp /etc/chrony.conf /var/lib/alterator/service/service-chrony/backups/chrony.conf.before_configure
    fi

    local old_servers=
    local new_servers=
    old_servers=$(grep -E '^server[[:space:]]' /etc/chrony.conf | awk '{print $2}')
    new_servers=$(echo "$input_json" | jq -r '.ntpServersSettings[]?.serverDomainName // empty')
    for old_server in $old_servers; do
        found=0
        for new_server in $new_servers; do
            if [ "$old_server" = "$new_server" ]; then
                found=1
                break
            fi
        done
        if [ $found -eq 0 ] && [ -n "$old_server" ]; then
            sed -i "/^server[[:space:]]\+$old_server\b.*/d" /etc/chrony.conf
        fi
    done

    local old_pools=
    local new_pools=
    old_pools=$(grep -E '^pool[[:space:]]' /etc/chrony.conf | awk '{print $2}')
    new_pools=$(echo "$input_json" | jq -r '.ntpPoolsSettings[]?.poolDomainName // empty')
    if [ -z "$new_pools" ]; then
        for old_pool in $old_pools; do
            if [ "$old_pool" = "pool.ntp.org" ]; then
                continue
            else
                sed -i "/^pool[[:space:]]\+$old_pool\b.*/d" /etc/chrony.conf
            fi
        done
    else
        for old_pool in $old_pools; do
            found=0
            for new_pool in $new_pools; do
                if [ "$old_pool" = "$new_pool" ]; then
                    found=1
                    break
                elif [ "$old_pool" = "pool.ntp.org" ]; then
                    found=1
                    break
                fi
            done
            if [ $found -eq 0 ] && [ -n "$old_pool" ]; then
                sed -i "/^pool[[:space:]]\+$old_pool\b.*/d" /etc/chrony.conf
            fi
        done
    fi

    local old_subnets=
    local new_subnets=
    old_subnets=$(grep -E '^allow[[:space:]]' /etc/chrony.conf | awk '{print $2}')
    new_subnets=$(echo "$input_json" | jq -r '.clientsSettings.subnetIpAddresses[]? // empty')
    for old_subnet in $old_subnets; do
        found=0
        for new_subnet in $new_subnets; do
            if [ "$old_subnet" = "$new_subnet" ]; then
                found=1     
                break
            fi
        done
        if [ $found -eq 0 ] && [ -n "$old_subnet" ]; then
            escaped_old_subnet=$(printf '%s\n' "$old_subnet" | sed -E 's/[\/&.]/\\&/g')
            sed -i "/^allow[[:space:]]\{1,\}${escaped_old_subnet}[[:space:]]*$/d" /etc/chrony.conf
        fi
    done
    
    echo "$input_json" > /var/lib/alterator/service/service-chrony/backups/configuring-config.json || retval=1

    keys=$(echo "$input_json" | jq -r 'keys[]')
    for key in $keys; do
        case "$key" in
            disableDefaultPoll)
                local default_pool_value=
                default_pool_value="$(parse_json "$input_json" "$key")"
                if [ -n "$default_pool_value" ] && [ "$default_pool_value" != "null" ] && [ "$default_pool_value" = "true" ]; then
                    sed -i '/^pool pool\.ntp\.org/ s/^/#/' /etc/chrony.conf
                    echo "Default pool of NTP servers is disabled"
                    flag=1
                fi
                if [ -n "$default_pool_value" ] && [ "$default_pool_value" != "null" ] && [ "$default_pool_value" = "false" ]; then
                    sed -i '/^#pool pool\.ntp\.org/ s/^#//' /etc/chrony.conf
                    echo "Default pool of NTP servers is enabled"
                    flag=0  
                fi  
                ;;
            makestep)
                local makestep_value=
                makestep_value="$(parse_json "$input_json" "$key")"
                if [ -n "$makestep_value" ] && [ "$makestep_value" != "null" ]; then
                    sed -i "s/^makestep .*/makestep ${makestep_value}/" /etc/chrony.conf 
                    echo "Makestep is set to ${makestep_value}"
                fi
                ;;
            rtcSync)
                local rtc_value=
                rtc_value="$(parse_json "$input_json" "$key")"
                if [ -n "$rtc_value" ] && [ "$rtc_value" = "false" ]
                then
                    sed -i '/^\s*rtcsync\s*$/d' /etc/chrony.conf
                    echo "RTC sync is canseled"
                else echo "RTC sync is set"
                fi
                ;;
            clientsSettings)
                local clients_json=
                local subnet_ips=
                local local_stratum=
                local clients_array=
                clients_array=$(echo "$input_json" | jq -c '.clientsSettings')
                if [ "$clients_array" != "null" ]; then
                    clients_json="$clients_array"

                    subnet_ips=$(echo "$clients_json" | jq -r '.subnetIpAddresses[]? // empty')
                    local_stratum=$(echo "$clients_json" | jq -r '.localStratum // empty')

                    for subnet_ip in $subnet_ips; do
                        if [ -n "$subnet_ip" ]; then
                            if grep -qE "^\s*#?\s*allow\s+$subnet_ip" /etc/chrony.conf; then
                                sed -i "s|^\s*#?\s*allow\s\+$subnet_ip.*|allow $subnet_ip|" /etc/chrony.conf
                            elif grep -q "^allow " /etc/chrony.conf; then
                                local last_subnet_line=
                                last_subnet_line=$(grep -n "^allow " /etc/chrony.conf | tail -n 1 | cut -d: -f1)
                                sed -i "${last_subnet_line}a allow $subnet_ip" /etc/chrony.conf
                                
                            else
                                sed -i "27i allow $subnet_ip" /etc/chrony.conf
                            fi
                        fi
                    done

                    if [ -n "$local_stratum" ]; then
                        if grep -qE '^\s*#?\s*local stratum' /etc/chrony.conf; then
                            sed -i "s|^\s*#\?\s*local stratum.*|local stratum $local_stratum|" /etc/chrony.conf
                        else
                            sed -i "29i local stratum $local_stratum" /etc/chrony.conf
                        fi
                    fi
                fi
                ;;
            ntpServersSettings)
                set_ntp_entry "server" "$input_json" ".ntpServersSettings" || retval=1
                ;;
            ntpPoolsSettings)
                set_ntp_entry "pool" "$input_json" ".ntpPoolsSettings" || retval=1
                ;;
            ntpDefaultPool)
                set_ntp_entry "default_pool" "$input_json" ".ntpDefaultPool" || retval=1
                ;;

            *)
               false
                ;;
            esac
    done

    return $retval
}

case "$MODE" in
    deploy)
        call_deploy || GLOBAL_EXIT=1
        ;;
    undeploy)
        call_undeploy || GLOBAL_EXIT=1
        ;;
    status)
        call_status 
        ;;
    backup)
        call_backup || GLOBAL_EXIT=1
        ;;
    restore)
        call_restore || GLOBAL_EXIT=1
        ;;
    start)
        call_start || GLOBAL_EXIT=1
        ;;
    stop)
        call_stop || GLOBAL_EXIT=1
        ;;
    configure)
        call_configure || GLOBAL_EXIT=1
        ;;
esac

exit $GLOBAL_EXIT
