#!/usr/bin/env bash

set -euo pipefail

IFS=$'\n\t'

SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
readonly DEFAULT_NTP_SERVER="pool.ntp.org"

log() {
  local level="$1"
  local source="$2"
  local message="$3"
  printf '[%s] [%s] [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$source" "$message" >&2
}

die() {
  log "ERROR" "$SCRIPT_NAME" "$1"
  exit 1
}

has_command() {
  command -v "$1" >/dev/null 2>&1
}

require_root() {
  if [[ "${EUID}" -ne 0 ]]; then
    die "Root privileges are required. Run: sudo bash $0"
  fi
}

detect_service_name() {
  local service_name

  for service_name in chrony chronyd; do
    if systemctl list-unit-files "${service_name}.service" >/dev/null 2>&1; then
      printf '%s\n' "$service_name"
      return 0
    fi
  done

  return 1
}

print_chrony_install_hint() {
  log "ERROR" "$SCRIPT_NAME" "No supported time synchronization tool was found."
  log "INFO" "$SCRIPT_NAME" "Install chrony, then run this script again."

  if has_command apt-get; then
    printf 'sudo apt-get update && sudo apt-get install -y chrony\n' >&2
  elif has_command dnf; then
    printf 'sudo dnf install -y chrony\n' >&2
  elif has_command yum; then
    printf 'sudo yum install -y chrony\n' >&2
  elif has_command pacman; then
    printf 'sudo pacman -Sy --needed chrony\n' >&2
  elif has_command zypper; then
    printf 'sudo zypper install -y chrony\n' >&2
  elif has_command apk; then
    printf 'sudo apk add chrony\n' >&2
  else
    printf 'Install package: chrony\n' >&2
  fi
}

sync_with_chrony() {
  local service_name=""

  if has_command systemctl && service_name="$(detect_service_name)"; then
    log "INFO" "$SCRIPT_NAME" "Enabling and starting ${service_name}.service."
    systemctl enable --now "${service_name}.service" >/dev/null
  fi

  log "INFO" "$SCRIPT_NAME" "Synchronizing system time with chrony."
  chronyc -a makestep
  chronyc tracking
  chronyc sources -v
}

sync_with_timedatectl() {
  log "WARN" "$SCRIPT_NAME" "chrony was not found. Falling back to timedatectl."
  log "INFO" "$SCRIPT_NAME" "Enabling NTP synchronization through systemd."
  timedatectl set-ntp true

  if has_command systemctl && systemctl list-unit-files systemd-timesyncd.service >/dev/null 2>&1; then
    systemctl restart systemd-timesyncd.service >/dev/null
  fi

  timedatectl status
}

sync_with_ntpdate() {
  local ntp_server="${1:-$DEFAULT_NTP_SERVER}"

  log "WARN" "$SCRIPT_NAME" "chrony and timedatectl were not found. Falling back to ntpdate."
  log "INFO" "$SCRIPT_NAME" "Synchronizing system time with ${ntp_server}."
  ntpdate -u "$ntp_server"
}

show_result() {
  log "INFO" "$SCRIPT_NAME" "Current system time: $(date '+%Y-%m-%d %H:%M:%S %Z')"
  log "INFO" "$SCRIPT_NAME" "Current UTC time: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
}

main() {
  local ntp_server="${1:-$DEFAULT_NTP_SERVER}"

  require_root

  if has_command chronyc; then
    sync_with_chrony
    show_result
    return 0
  fi

  if has_command timedatectl; then
    sync_with_timedatectl
    show_result
    return 0
  fi

  if has_command ntpdate; then
    sync_with_ntpdate "$ntp_server"
    show_result
    return 0
  fi

  print_chrony_install_hint
  exit 1
}

main "$@"
