#!/bin/bash
#
# timedatectl - control the system time and date
# Bash implementation for systems using timedated without systemd.
#
# rizitis 2026, GPLv2+

DBUS_DEST="org.freedesktop.timedate1"
DBUS_PATH="/org/freedesktop/timedate1"
DBUS_IFACE="org.freedesktop.timedate1"

die() {
  echo "timedatectl: $*" >&2
  exit 1
}

need_busctl() {
  command -v busctl &>/dev/null || die "busctl not found"
}

get_property() {
  busctl get-property "$DBUS_DEST" "$DBUS_PATH" "$DBUS_IFACE" "$1" 2>/dev/null | cut -d' ' -f2- | tr -d '"'
}

cmd_status() {
  need_busctl

  local timezone local_rtc can_ntp use_ntp ntp_sync
  local time_now rtc_time

  timezone=$(get_property Timezone)
  local_rtc=$(get_property LocalRTC)
  can_ntp=$(get_property CanNTP)
  use_ntp=$(get_property NTP)
  ntp_sync=$(get_property NTPSynchronized)

  # format booleans
  local_rtc_str="no"
  [ "$local_rtc" = "true" ] && local_rtc_str="yes"
  can_ntp_str="no"
  [ "$can_ntp" = "true" ] && can_ntp_str="yes"
  use_ntp_str="no"
  [ "$use_ntp" = "true" ] && use_ntp_str="yes"
  ntp_sync_str="no"
  [ "$ntp_sync" = "true" ] && ntp_sync_str="yes"

  time_now=$(date)
  rtc_time=$(hwclock --show 2>/dev/null | head -1 || echo "n/a")

  printf "               Local time: %s\n" "$time_now"
  printf "           Universal time: %s\n" "$(date -u)"
  printf "                 RTC time: %s\n" "$rtc_time"
  printf "                Time zone: %s\n" "$timezone"
  printf "              NTP enabled: %s\n" "$use_ntp_str"
  printf "         NTP synchronized: %s\n" "$ntp_sync_str"
  printf "          RTC in local TZ: %s\n" "$local_rtc_str"
  printf "               CanNTP: %s\n"     "$can_ntp_str"
}

cmd_set_timezone() {
  need_busctl
  [ -z "$1" ] && die "set-timezone: missing timezone argument"
  busctl call "$DBUS_DEST" "$DBUS_PATH" "$DBUS_IFACE" SetTimezone sb "$1" false \
    || die "Failed to set timezone"
}

cmd_set_local_rtc() {
  need_busctl
  local val="$1"
  [ -z "$val" ] && die "set-local-rtc: missing argument (0 or 1)"
  case "$val" in
    0|false|no)  val_bool="false" ;;
    1|true|yes)  val_bool="true"  ;;
    *) die "set-local-rtc: invalid argument '$val' (use 0 or 1)" ;;
  esac
  busctl call "$DBUS_DEST" "$DBUS_PATH" "$DBUS_IFACE" SetLocalRTC bbb "$val_bool" false false \
    || die "Failed to set local RTC"
}

cmd_set_ntp() {
  need_busctl
  local val="$1"
  [ -z "$val" ] && die "set-ntp: missing argument (0 or 1)"
  case "$val" in
    0|false|no)  val_bool="false" ;;
    1|true|yes)  val_bool="true"  ;;
    *) die "set-ntp: invalid argument '$val' (use 0 or 1)" ;;
  esac
  busctl call "$DBUS_DEST" "$DBUS_PATH" "$DBUS_IFACE" SetNTP bb "$val_bool" false \
    || die "Failed to set NTP"
}

cmd_list_timezones() {
  need_busctl
  busctl call "$DBUS_DEST" "$DBUS_PATH" "$DBUS_IFACE" ListTimezones \
    | tr ' ' '\n' | grep '/' | tr -d '"' | sort
}

cmd_show() {
  need_busctl

  local timezone local_rtc can_ntp use_ntp ntp_sync
  timezone=$(get_property Timezone)
  local_rtc=$(get_property LocalRTC)
  can_ntp=$(get_property CanNTP)
  use_ntp=$(get_property NTP)
  ntp_sync=$(get_property NTPSynchronized)

  printf "Timezone=%s\n"         "$timezone"
  printf "LocalRTC=%s\n"         "$local_rtc"
  printf "CanNTP=%s\n"           "$can_ntp"
  printf "NTP=%s\n"              "$use_ntp"
  printf "NTPSynchronized=%s\n"  "$ntp_sync"
  printf "TimeUSec=%s\n"         "$(date +%s)000000"
  printf "RTCTimeUSec=%s\n"      "$(hwclock --show 2>/dev/null | awk '{print $1"T"$2}' || echo n/a)"
}

usage() {
  cat <<EOF
Usage: timedatectl [OPTIONS] COMMAND

Commands:
  status                   Show current time settings
  set-timezone ZONE        Set the system timezone (e.g. Europe/Athens)
  set-local-rtc [0|1]      Control whether RTC is in local time
  set-ntp [0|1]            Enable or disable NTP synchronization
  list-timezones           List available timezones
  show                     Show settings in key=value format

Options:
  -h, --help               Show this help
EOF
}

# main
case "$1" in
  ""|status)        cmd_status ;;
  set-timezone)     cmd_set_timezone "$2" ;;
  set-local-rtc)    cmd_set_local_rtc "$2" ;;
  set-ntp)          cmd_set_ntp "$2" ;;
  list-timezones)   cmd_list_timezones ;;
  show)             cmd_show ;;
  -h|--help)        usage ;;
  *)                die "Unknown command '$1'. Try --help." ;;
esac
