#!/usr/bin/bash

# ==============================================================================
# stillOS Weekly Active User Counter Client
#
# Sends a privacy-preserving ping to a configured server once per day.
# The server uses the included UUID (rotated weekly) to count unique users
# per week.
# ==============================================================================

# --- Configuration File ---
# Expected location: /etc/stillcount/count.conf
# Format:
# COUNT_URL="http://your-server.com/ping"
# VARIANT_ID="gnome"
# UPDATE_ID="2025.05-hotfix1"
CONFIG_FILE="/etc/stillcount/count.conf"

# --- State Directory and File ---
# Stores the current UUID and the timestamp it was generated.
# Needs appropriate permissions (e.g., readable/writable by root or a dedicated user).
STATE_DIR="/var/lib/stillcount-count"
UUID_FILE="$STATE_DIR/uuid"

# --- Default Configuration (if config file is missing or values are unset) ---
DEFAULT_COUNT_URL="http://count.stillinfra.com/ping"
DEFAULT_VARIANT_ID="unknown"
DEFAULT_UPDATE_ID="unknown"

# --- Function to log messages ---
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - StillOS Counter: $1"
    # Consider logging to syslog as well for systemd integration
    # logger -t stillcount-counter "$1"
}

# --- Ensure state directory exists ---
if [ ! -d "$STATE_DIR" ]; then
    mkdir -p "$STATE_DIR"
    if [ $? -ne 0 ]; then
        log_message "ERROR: Could not create state directory: $STATE_DIR"
        exit 1
    fi
    # Set permissions appropriately - adjust if not running as root
    chmod 700 "$STATE_DIR"
    log_message "Created state directory: $STATE_DIR"
fi

# --- Read Configuration ---
COUNT_URL="$DEFAULT_COUNT_URL"
VARIANT_ID="$DEFAULT_VARIANT_ID"
UPDATE_ID="$DEFAULT_UPDATE_ID"

if [ -f "$CONFIG_FILE" ]; then
    # Source the config file carefully
    # Check for potentially harmful commands before sourcing, or use more robust parsing
    # For simplicity, we'll source directly, assuming the file is trusted.
    # shellcheck source=/dev/null
    source "$CONFIG_FILE"
    log_message "Loaded configuration from $CONFIG_FILE"
else
    log_message "WARNING: Configuration file not found: $CONFIG_FILE. Using defaults."
fi

# Use defaults if variables are empty after sourcing
COUNT_URL="${COUNT_URL:-$DEFAULT_COUNT_URL}"
VARIANT_ID="${VARIANT_ID:-$DEFAULT_VARIANT_ID}"
UPDATE_ID="${UPDATE_ID:-$DEFAULT_UPDATE_ID}"

# --- UUID Management ---
CURRENT_UUID=""
CURRENT_ISO_WEEK=$(date +%G-W%V) # Get current year and ISO week number (e.g., 2025-W19)

# Check if UUID file exists and read its content
if [ -f "$UUID_FILE" ]; then
    # File format: UUID|YYYY-WW (e.g., xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx|2025-W19)
    read -r STORED_DATA < "$UUID_FILE"
    STORED_UUID=$(echo "$STORED_DATA" | cut -d'|' -f1)
    STORED_ISO_WEEK=$(echo "$STORED_DATA" | cut -d'|' -f2)

    # Validate stored data format (basic check)
    if [[ "$STORED_UUID" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ && "$STORED_ISO_WEEK" =~ ^[0-9]{4}-W[0-9]{2}$ ]]; then
        # Check if the stored week matches the current week
        if [ "$STORED_ISO_WEEK" == "$CURRENT_ISO_WEEK" ]; then
            # Week matches, use the stored UUID
            CURRENT_UUID="$STORED_UUID"
            log_message "Current week ($CURRENT_ISO_WEEK) matches stored week. Using existing UUID: $CURRENT_UUID"
        else
            # Week mismatch, generate a new UUID
            log_message "Stored week ($STORED_ISO_WEEK) differs from current week ($CURRENT_ISO_WEEK). Generating new UUID."
            CURRENT_UUID=$(uuidgen)
            echo "$CURRENT_UUID|$CURRENT_ISO_WEEK" > "$UUID_FILE"
            if [ $? -ne 0 ]; then
                 log_message "ERROR: Could not write new UUID to $UUID_FILE"
                 # Decide if you want to exit or try to proceed without persisting
                 exit 1
            fi
            log_message "Generated and stored new UUID: $CURRENT_UUID for week $CURRENT_ISO_WEEK"
        fi
    else
        log_message "WARNING: Invalid data format in $UUID_FILE. Generating new UUID."
        CURRENT_UUID=$(uuidgen)
        echo "$CURRENT_UUID|$CURRENT_ISO_WEEK" > "$UUID_FILE"
         if [ $? -ne 0 ]; then
             log_message "ERROR: Could not write new UUID to $UUID_FILE"
             exit 1
         fi
        log_message "Generated and stored new UUID: $CURRENT_UUID for week $CURRENT_ISO_WEEK"
    fi
else
    # UUID file doesn't exist, generate a new UUID
    log_message "UUID file not found ($UUID_FILE). Generating new UUID."
    CURRENT_UUID=$(uuidgen)
    echo "$CURRENT_UUID|$CURRENT_ISO_WEEK" > "$UUID_FILE"
     if [ $? -ne 0 ]; then
         log_message "ERROR: Could not write new UUID to $UUID_FILE"
         exit 1
     fi
    log_message "Generated and stored new UUID: $CURRENT_UUID for week $CURRENT_ISO_WEEK"
fi

# Final check if we have a UUID
if [ -z "$CURRENT_UUID" ]; then
    log_message "ERROR: Failed to obtain a UUID. Exiting."
    exit 1
fi

# --- Prepare JSON Payload ---
JSON_PAYLOAD=$(cat <<EOF
{
  "uuid": "$CURRENT_UUID",
  "variant_id": "$VARIANT_ID",
  "update_id": "$UPDATE_ID"
}
EOF
)

# --- Send Ping ---
log_message "Sending ping to $COUNT_URL"
HTTP_RESPONSE=$(curl --silent --show-error --request POST \
     --header "Content-Type: application/json" \
     --data "$JSON_PAYLOAD" \
     --connect-timeout 10 \
     --max-time 30 \
     --write-out "\nHTTP_STATUS:%{http_code}" \
     "$COUNT_URL")

# Extract status code and response body
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n1 | sed 's/.*://')
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d') # Remove last line (status code)

# Check HTTP status code
if [ "$HTTP_STATUS" -ge 200 ] && [ "$HTTP_STATUS" -lt 300 ]; then
    log_message "Ping successful (HTTP $HTTP_STATUS). Response: $HTTP_BODY"
    exit 0
elif [ "$HTTP_STATUS" == "429" ]; then
     log_message "WARNING: Ping rejected due to rate limiting (HTTP $HTTP_STATUS). Will retry later. Response: $HTTP_BODY"
     exit 1 # Indicate failure for retry logic if using systemd timers
else
    log_message "ERROR: Ping failed (HTTP $HTTP_STATUS). Response: $HTTP_BODY"
    # Log curl error if any (captured by --show-error, might be in HTTP_BODY or stderr)
    exit 1 # Indicate failure
fi

