#!/usr/bin/env bash

# ============================================
# Config
# ============================================

MONITOR_DIR="$(ctx::root)/daemon"
WATCHLIST_FILE="${MONITOR_DIR}/watchlist.json"
EVENTS_LOG="${MONITOR_DIR}/events.log"
MONITOR_SERVICE="wgctl-monitor"

# ============================================
# Lifecycle
# ============================================

function monitor::on_load() {
  if [[ ! -f "$WATCHLIST_FILE" ]]; then
    echo '{}' > "$WATCHLIST_FILE"
  fi
  if [[ ! -f "$EVENTS_LOG" ]]; then
    touch "$EVENTS_LOG"
  fi
}

# ============================================
# Watchlist
# ============================================

function monitor::watch() {
  local ip="$1" client="$2"
  json::set "$WATCHLIST_FILE" "$ip" "$client"
  log::wg "Watching: ${client} (${ip})"
}

function monitor::unwatch() {
  local ip="$1"
  json::delete "$WATCHLIST_FILE" "$ip"
}

function monitor::is_watched() {
  local ip="$1"
  python3 -c "
import json
with open('${WATCHLIST_FILE}') as f:
    wl = json.load(f)
exit(0 if '${ip}' in wl else 1)
"
}

function monitor::unwatch_client() {
  local name="$1"
  python3 -c "
import json
with open('${WATCHLIST_FILE}') as f:
    wl = json.load(f)
wl = {k: v for k, v in wl.items() if v != '${name}'}
with open('${WATCHLIST_FILE}', 'w') as f:
    json.dump(wl, f, indent=2)
"
  log::wg "Unwatched client: ${name}"
}

# ============================================
# Events
# ============================================

function monitor::last_attempt() {
  local client="$1"
  python3 -c "
import json

events = []
try:
    with open('${EVENTS_LOG}') as f:
        for line in f:
            try:
                e = json.loads(line.strip())
                if e.get('client') == '${client}':
                    events.append(e)
            except:
                pass
except:
    pass

if events:
    print(events[-1].get('timestamp', ''))
"
}

function monitor::last_endpoint() {
  local client="$1"
  python3 -c "
import json

events = []
try:
    with open('${EVENTS_LOG}') as f:
        for line in f:
            try:
                e = json.loads(line.strip())
                if e.get('client') == '${client}' and e.get('endpoint'):
                    events.append(e)
            except:
                pass
except:
    pass

if events:
    print(events[-1].get('endpoint', ''))
"
}

function monitor::events_for() {
  local ip="$1"
  local limit="${2:-50}"
  python3 -c "
import json
from datetime import datetime, timezone

events = []
try:
    with open('${EVENTS_LOG}') as f:
        for line in f:
            try:
                e = json.loads(line.strip())
                if e.get('ip') == '${ip}':
                    events.append(e)
            except:
                pass
except:
    pass

for e in events[-${limit}:]:
    ts = e.get('timestamp', '')
    try:
        dt = datetime.fromisoformat(ts)
        ts = dt.strftime('%Y-%m-%d %H:%M:%S')
    except:
        pass
    endpoint = e.get('endpoint', '—')
    client   = e.get('client', '—')
    event    = e.get('event', '—')
    print(f'  {ts}  {client:<20} {endpoint:<20} {event}')
"
}

# ============================================
# Endpoint Cache (for blocked clients)
# ============================================

ENDPOINT_CACHE="${WGCTL_DIR}/daemon/endpoint_cache.json"

function monitor::cache_endpoint() {
  local client="$1" ip="$2"
  json::set "$ENDPOINT_CACHE" "$client" "$ip"
}

function monitor::get_cached_endpoint() {
  local client="$1"
  json::get "$ENDPOINT_CACHE" "$client"
}

function monitor::update_endpoint_cache() {
  while IFS=$'\t' read -r key endpoint; do
    [[ "$endpoint" == "(none)" ]] && continue
    local ip
    ip=$(echo "$endpoint" | cut -d':' -f1)
    local client
    client=$(keys::find_by_public "$key") || continue
    monitor::cache_endpoint "$client" "$ip"
  done < <(wg show "$(config::interface)" endpoints 2>/dev/null)
}

# ============================================
# Endpoint (from wg show, for active clients)
# ============================================

function monitor::endpoint_for_key() {
  local public_key="$1"
  wg show "$(config::interface)" endpoints 2>/dev/null \
    | grep "^${public_key}" \
    | awk '{print $2}' \
    | cut -d':' -f1
}

# ============================================
# Service
# ============================================

function monitor::start() {
  systemctl start "$MONITOR_SERVICE"
  log::wg_start "Monitor daemon started"
}

function monitor::stop() {
  systemctl stop "$MONITOR_SERVICE"
  log::wg_stop "Monitor daemon stopped"
}

function monitor::restart() {
  systemctl restart "$MONITOR_SERVICE"
  log::wg_start "Monitor daemon restarted"
}

function monitor::is_running() {
  systemctl is-active --quiet "$MONITOR_SERVICE"
}
