#!/bin/bash
# Linesync Sidecar Entrypoint
# Supports multiple modes of operation for configuration synchronization

set -e

# =============================================================================
# UID/GID Auto-Detection and Privilege Dropping
# =============================================================================
# If running as root, detect the UID/GID from mounted directories and drop
# privileges to match. This allows bind mounts to work without manual -u flags.

if [ "$(id -u)" = "0" ]; then
    # Detect UID/GID from mounted directories (in order of preference)
    TARGET_UID=""
    TARGET_GID=""

    for detect_path in /home/linesync/ircd/ircd.conf ; do
        if [ -d "$detect_path" ]; then
            TARGET_UID=$(stat -c %u "$detect_path")
            TARGET_GID=$(stat -c %g "$detect_path")
            # Skip if owned by root (probably not a bind mount)
            if [ "$TARGET_UID" != "0" ]; then
                break
            fi
        fi
    done

    # Default to 1000:1000 if detection failed or got root
    : "${TARGET_UID:=1000}"
    : "${TARGET_GID:=1000}"

    # Get current linesync UID/GID
    CURRENT_UID=$(id -u linesync)
    CURRENT_GID=$(id -g linesync)

    # Modify user/group if needed
    if [ "$TARGET_GID" != "$CURRENT_GID" ]; then
        groupmod -g "$TARGET_GID" linesync 2>/dev/null || true
    fi
    if [ "$TARGET_UID" != "$CURRENT_UID" ]; then
        usermod -u "$TARGET_UID" linesync 2>/dev/null || true
    fi

    # Fix ownership of home directory
    chown -R linesync:linesync /home/linesync 2>/dev/null || true

    # Ensure SSH config exists
    if [ ! -f /home/linesync/.ssh/config ]; then
        mkdir -p /home/linesync/.ssh
        echo -e "Host *\n  StrictHostKeyChecking accept-new\n  UserKnownHostsFile /home/linesync/.ssh/known_hosts" > /home/linesync/.ssh/config
        chmod 700 /home/linesync/.ssh
        chmod 600 /home/linesync/.ssh/config
        chown -R linesync:linesync /home/linesync/.ssh
    fi

    # Re-exec this script as linesync user
    exec gosu linesync "$0" "$@"
fi

# =============================================================================
# Main Entrypoint (running as linesync user)
# =============================================================================

# Configuration with defaults
: "${SYNC_INTERVAL:=300}"           # Sync interval in seconds (default: 5 minutes)
: "${IRCD_CONF:=/home/linesync/ircd/ircd.conf}"
: "${IRCD_PID:=/home/linesync/ircd/ircd.pid}"
: "${SSH_KEY:=/home/linesync/.ssh/id_ed25519}"
: "${NEFARIOUS_CONTAINER:=nefarious}"
: "${GIT_REPOSITORY:=}"
: "${CERT_TAG:=}"
: "${CERT_FILE:=}"                  # Output path for certificate (default: fullchain.pem in conf dir)

GITSYNC="/home/linesync/gitsync.sh"

show_help() {
    echo "Linesync Sidecar Container"
    echo ""
    echo "Modes:"
    echo "  keygen              Generate a new SSH keypair for git authentication"
    echo "  setup               Clone the linesync git repository (initial setup)"
    echo "  sync                Run continuous sync loop (default)"
    echo "  once                Run sync once and exit"
    echo "  shell               Start an interactive shell"
    echo "  help                Show this help message"
    echo ""
    echo "Environment Variables:"
    echo "  SYNC_INTERVAL       Seconds between sync attempts (default: 300)"
    echo "  IRCD_CONF           Path to ircd.conf (default: /home/linesync/ircd/ircd.conf)"
    echo "  IRCD_PID            Path to ircd.pid (default: /home/linesync/ircd/ircd.pid)"
    echo "  SSH_KEY             Path to SSH private key (default: /home/linesync/.ssh/id_ed25519)"
    echo "  NEFARIOUS_CONTAINER Name of nefarious container to signal (default: nefarious)"
    echo "  GIT_REPOSITORY      Git repository URL (required for setup mode)"
    echo "  CERT_TAG            Git tag for SSL certificate (optional)"
    echo "  CERT_FILE           Output path for certificate (default: fullchain.pem in conf dir)"
    echo ""
    echo "Volume Mounts:"
    echo "  /home/linesync/.ssh         SSH keys directory"
    echo "  /home/linesync/ircd         IRCd config directory (shared with nefarious)"
    echo "  /var/run/docker.sock        Docker socket (for sending SIGHUP)"
    echo ""
}

# Generate SSH keypair
do_keygen() {
    local keytype="${1:-ed25519}"
    local sshdir="/home/linesync/.ssh"
    local keyfile="${sshdir}/id_${keytype}"

    # Check if .ssh directory exists
    if [ ! -d "$sshdir" ]; then
        echo "Error: SSH directory $sshdir does not exist"
        echo "Create the directory on the host first: mkdir -p ./linesync-ssh"
        exit 1
    fi

    # Check if directory is writable
    if [ ! -w "$sshdir" ]; then
        echo "Error: SSH directory $sshdir is not writable"
        echo "Check that the directory exists and has correct permissions"
        exit 1
    fi

    # Ensure proper directory permissions
    chmod 700 "$sshdir" 2>/dev/null || true

    if [ -f "$keyfile" ]; then
        echo "Key already exists at $keyfile"
        echo "Public key:"
        cat "${keyfile}.pub"
        return 0
    fi

    echo "Generating ${keytype} keypair..."
    ssh-keygen -t "$keytype" -f "$keyfile" -N "" -C "linesync@$(hostname)"

    # Set proper permissions on the key files
    chmod 600 "$keyfile"
    chmod 644 "${keyfile}.pub"

    echo ""
    echo "Key generated successfully!"
    echo ""
    echo "Public key (add this to your git repository's deploy keys):"
    echo "================================================================"
    cat "${keyfile}.pub"
    echo "================================================================"
}

# Initial repository setup
do_setup() {
    if [ -z "$GIT_REPOSITORY" ]; then
        echo "Error: GIT_REPOSITORY environment variable is required for setup"
        exit 1
    fi

    if [ ! -f "$SSH_KEY" ]; then
        echo "Error: SSH key not found at $SSH_KEY"
        echo "Run 'keygen' mode first to create a keypair"
        exit 1
    fi

    echo "Setting up linesync repository..."
    echo "Repository: $GIT_REPOSITORY"
    echo "SSH Key: $SSH_KEY"
    echo "Config: $IRCD_CONF"

    # Run gitsync.sh in setup mode
    "$GITSYNC" -s "$SSH_KEY" -i "$GIT_REPOSITORY" "$IRCD_CONF" "$IRCD_PID"
}

# Signal nefarious container to reload config
signal_reload() {
    if [ -S /var/run/docker.sock ]; then
        echo "Sending SIGHUP to container: $NEFARIOUS_CONTAINER"
        docker kill --signal=SIGHUP "$NEFARIOUS_CONTAINER" 2>/dev/null || \
            echo "Warning: Could not signal container (may not be running)"
    else
        echo "Warning: Docker socket not available, cannot signal container"
        echo "Config changes will take effect on next ircd restart"
    fi
}

# Run a single sync
do_sync_once() {
    local sync_args="-s $SSH_KEY"

    if [ -n "$CERT_TAG" ]; then
        sync_args="$sync_args -c $CERT_TAG"
        if [ -n "$CERT_FILE" ]; then
            sync_args="$sync_args -C $CERT_FILE"
        fi
    fi

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Running sync..."

    # Create a wrapper that signals via docker instead of using PID file
    # We'll run gitsync.sh but handle the signaling ourselves
    local tmp_pid="/tmp/fake.pid"
    echo "99999" > "$tmp_pid"

    # Capture gitsync output to check if changes were made
    local before_md5=""
    local after_md5=""

    if [ -f "$IRCD_CONF" ]; then
        before_md5=$(md5sum "$IRCD_CONF" 2>/dev/null | cut -d' ' -f1)
    fi

    # Run gitsync (it will try to HUP pid 99999 which will fail silently)
    "$GITSYNC" $sync_args "$IRCD_CONF" "$tmp_pid" 2>&1 || true

    if [ -f "$IRCD_CONF" ]; then
        after_md5=$(md5sum "$IRCD_CONF" 2>/dev/null | cut -d' ' -f1)
    fi

    # If config changed, signal the container
    if [ "$before_md5" != "$after_md5" ] && [ -n "$after_md5" ]; then
        echo "Configuration changed, signaling reload..."
        signal_reload
    fi

    rm -f "$tmp_pid"
}

# Continuous sync loop
do_sync_loop() {
    # Handle shutdown signals gracefully
    trap 'echo "[$(date "+%Y-%m-%d %H:%M:%S")] Shutting down..."; exit 0' SIGTERM SIGINT

    echo "Starting linesync daemon"
    echo "Sync interval: ${SYNC_INTERVAL}s"
    echo "Config: $IRCD_CONF"
    echo "Container: $NEFARIOUS_CONTAINER"
    echo ""

    # Check prerequisites
    if [ ! -f "$SSH_KEY" ]; then
        echo "Error: SSH key not found at $SSH_KEY"
        echo "Run 'keygen' mode first, or mount your key"
        exit 1
    fi

    local linesync_dir
    linesync_dir=$(dirname "$IRCD_CONF")/linesync

    if [ ! -d "$linesync_dir" ]; then
        echo "Error: Linesync repository not found at $linesync_dir"
        echo "Run 'setup' mode first to clone the repository"
        exit 1
    fi

    # Main loop
    while true; do
        do_sync_once
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sleeping ${SYNC_INTERVAL}s..."
        # Sleep in background so trap can interrupt
        sleep "$SYNC_INTERVAL" &
        wait $!
    done
}

# Main entrypoint
case "${1:-sync}" in
    keygen)
        do_keygen "${2:-ed25519}"
        ;;
    setup)
        do_setup
        ;;
    sync)
        do_sync_loop
        ;;
    once)
        do_sync_once
        ;;
    shell|bash|sh)
        exec /bin/bash
        ;;
    help|--help|-h)
        show_help
        ;;
    *)
        echo "Unknown command: $1"
        show_help
        exit 1
        ;;
esac
