#!/usr/bin/env bash
#
#  The purpose of this script is to synchronize the local server time with a provided http server which reply by curl 
#  correct date time. The time precision with this script is about 2s.
#
#  The default http url FQN is 'https://www.timeanddate.com/worldclock/france/paris'
#  The default date format used is "%Y-%m-%d %H:%M:%S". 
#   
# Args: 
# Opts:
#  $1 :  The full qualified url of the http server from which date and time are gotten.
#  $2 :  The date format to which the local server date time is set to. 
#
# Depends on: curl
#
# Usage: sudo -E /papi/infra/scripts/SynchronizeLocalTimeWithHttpServer.sh  https://google.fr
set -euo pipefail

SCRIPT_NAME=$(readlink -f ${BASH_SOURCE[0]})

if [ "$EUID" -ne 0 ];then 
  printf "The script ${SCRIPT_NAME}  must be run as root or with 'sudo -E'\n"
  exit -10
fi


# -----------------------------
# CONFIGURATION (Open/Closed: add sources here)
# -----------------------------
readonly TIME_SOURCES=(
  "https://google.com"
  "https://cloudflare.com"
  "https://api.github.com"
)
readonly TIMEOUT=3
readonly SYSTEM_TZ="${TIMEZONE:-$(timedatectl show -p Timezone --value 2>/dev/null || echo UTC)}"

# -----------------------------
# SINGLE RESPONSIBILITY: Fetch time from one URL
# -----------------------------
fetch_http_date() {
  local url="$1"
  curl -sI --max-time "$TIMEOUT" "$url" 2>/dev/null \
    | grep -i '^Date:' \
    | head -1 \
    | sed 's/^[Dd]ate:[[:space:]]*//'
}

# -----------------------------
# SINGLE RESPONSIBILITY: Get time from available sources (Liskov: any HTTPS endpoint works)
# -----------------------------
get_time_from_sources() {
  local url date_header

  for url in "${TIME_SOURCES[@]}"; do
    date_header=$(fetch_http_date "$url" || true)
    if [[ -n "$date_header" ]]; then
      printf '%s\n%s\n' "$date_header" "$url"
      return 0
    fi
  done
  return 1
}

# -----------------------------
# SINGLE RESPONSIBILITY: Convert HTTP date to local time
# -----------------------------
convert_to_local() {
  local http_date="$1"
  TZ="$SYSTEM_TZ" date -d "$http_date" +"%Y-%m-%d %H:%M:%S %Z (%z)" 2>/dev/null
}

# -----------------------------
# SINGLE RESPONSIBILITY: Apply time to system (Dependency Inversion: abstracts "setter")
# -----------------------------
apply_system_time() {
  local http_date="$1"

  [[ $EUID -ne 0 ]] && return 0

  date -s "$http_date" >/dev/null 2>&1
  hwclock -w >/dev/null 2>&1 || true
}

# -----------------------------
# MAIN: Composition root (Interface Segregation: minimal coordination)
# -----------------------------
main() {
  local result http_date source local_time

  result=$(get_time_from_sources) || {
    echo "Failed to fetch time from configured sources" >&2
    exit 1
  }

  # Parse result (two-line format: date\nsource)
  http_date=$(echo "$result" | sed -n '1p')
  source=$(echo "$result" | sed -n '2p')

  local_time=$(convert_to_local "$http_date")

  echo "Source: $source"
  echo "Local Time ($SYSTEM_TZ): $local_time"

  apply_system_time "$http_date"

  echo "Sync completed"
}

# Entry point
main "$@"

