#!/bin/bash
# ROA2WEB SSH Tunnel Manager (Multi-Server Support)
# Manages SSH tunnels to Oracle server(s) for development
#
# Configuration:
#   - Reads from backend/ssh-tunnels.json (next to .env)
#   - SSH passwords from backend/secrets/{server_id}.ssh_pass
#   - SSH keys from backend/secrets/{server_id}.ssh_key or ssh_key field in config
#   - Falls back to legacy single-server config from backend/.env if JSON not found
#
# Usage: ./ssh-tunnel.sh {start|stop|status|restart|help}

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="$SCRIPT_DIR/backend/.env"
SECRETS_DIR="$SCRIPT_DIR/backend/secrets"
SSH_TUNNELS_FILE="$SCRIPT_DIR/backend/ssh-tunnels.json"
PID_DIR="/tmp/roa_tunnels"
mkdir -p "$PID_DIR"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'

# ============================================================================
# Parse configuration from .env and secrets/
# ============================================================================
# Global arrays to store tunnel configs
declare -a SERVER_IDS
declare -A SERVER_NAMES
declare -A LOCAL_PORTS
declare -A SSH_HOSTS
declare -A SSH_PORTS
declare -A SSH_USERS
declare -A SSH_PASSWORDS
declare -A SSH_KEYS
declare -A ORACLE_HOSTS
declare -A ORACLE_PORTS

parse_config() {
    SERVER_IDS=()

    # Primary: Read from secrets/ssh-tunnels.json
    if [ -f "$SSH_TUNNELS_FILE" ]; then
        echo -e "${CYAN}Reading config from: $SSH_TUNNELS_FILE${NC}"
        # Parse JSON with Python
        eval "$(python3 << PYTHON_SCRIPT
import json
import os

secrets_dir = "$SECRETS_DIR"
tunnels_file = "$SSH_TUNNELS_FILE"

with open(tunnels_file, 'r') as f:
    tunnels = json.load(f)

for t in tunnels:
    sid = t.get('id', 'default')
    ssh_host = t.get('ssh_host', '')

    # Skip entries without ssh_host
    if not ssh_host:
        print(f'# Skipping [{sid}] - no ssh_host configured')
        continue

    print(f'SERVER_IDS+=("{sid}")')
    print(f'SERVER_NAMES["{sid}"]="{t.get("name", sid)}"')
    print(f'LOCAL_PORTS["{sid}"]="{t.get("local_port", 1521)}"')
    print(f'SSH_HOSTS["{sid}"]="{ssh_host}"')
    print(f'SSH_PORTS["{sid}"]="{t.get("ssh_port", 22)}"')
    print(f'SSH_USERS["{sid}"]="{t.get("ssh_user", "root")}"')
    print(f'ORACLE_HOSTS["{sid}"]="{t.get("oracle_host", "localhost")}"')
    print(f'ORACLE_PORTS["{sid}"]="{t.get("oracle_port", 1521)}"')

    # SSH key path (from config or default)
    ssh_key = t.get('ssh_key', f'{secrets_dir}/{sid}.ssh_key')
    # Resolve relative paths
    if not ssh_key.startswith('/'):
        ssh_key = f'$SCRIPT_DIR/backend/{ssh_key}'
    print(f'SSH_KEYS["{sid}"]="{ssh_key}"')
PYTHON_SCRIPT
)"
        # Load SSH passwords from secrets files
        for sid in "${SERVER_IDS[@]}"; do
            local pass_file="$SECRETS_DIR/${sid}.ssh_pass"
            if [ -f "$pass_file" ]; then
                SSH_PASSWORDS["$sid"]="$(cat "$pass_file" | tr -d '\n')"
            fi
        done
    fi

    # Fallback: Legacy single-server config from .env
    if [ ${#SERVER_IDS[@]} -eq 0 ]; then
        if [ -f "$ENV_FILE" ]; then
            echo -e "${YELLOW}No ssh-tunnels.json found, using legacy config from .env${NC}"
            # Source .env for legacy vars
            set -a
            source "$ENV_FILE"
            set +a
        fi

        SERVER_IDS+=("default")
        SERVER_NAMES["default"]="Default Server (Legacy)"
        LOCAL_PORTS["default"]="${ORACLE_PORT:-1521}"
        SSH_HOSTS["default"]="${SSH_HOST:-roa.romfast.ro}"
        SSH_PORTS["default"]="${SSH_PORT:-22122}"
        SSH_USERS["default"]="${SSH_USER:-roa2web}"
        ORACLE_HOSTS["default"]="${ORACLE_TUNNEL_REMOTE:-10.0.20.36}"
        ORACLE_PORTS["default"]="${ORACLE_TUNNEL_PORT:-1521}"
        SSH_KEYS["default"]="$SECRETS_DIR/roa_oracle_server"

        # Legacy password file
        if [ -f "$SECRETS_DIR/default.ssh_pass" ]; then
            SSH_PASSWORDS["default"]="$(cat "$SECRETS_DIR/default.ssh_pass" | tr -d '\n')"
        fi
    fi
}

# ============================================================================
# Tunnel management functions
# ============================================================================

get_pid_file() {
    local sid=$1
    echo "$PID_DIR/tunnel_${sid}.pid"
}

check_tunnel() {
    local sid=$1
    local pid_file=$(get_pid_file "$sid")

    if [ -f "$pid_file" ]; then
        local pid=$(cat "$pid_file")
        if ps -p "$pid" > /dev/null 2>&1; then
            return 0  # Running
        else
            rm -f "$pid_file"
        fi
    fi
    return 1  # Not running
}

start_single_tunnel() {
    local sid=$1
    local name="${SERVER_NAMES[$sid]}"
    local local_port="${LOCAL_PORTS[$sid]}"
    local ssh_host="${SSH_HOSTS[$sid]}"
    local ssh_port="${SSH_PORTS[$sid]}"
    local ssh_user="${SSH_USERS[$sid]}"
    local ssh_key="${SSH_KEYS[$sid]}"
    local ssh_pass="${SSH_PASSWORDS[$sid]}"
    local oracle_host="${ORACLE_HOSTS[$sid]}"
    local oracle_port="${ORACLE_PORTS[$sid]}"
    local pid_file=$(get_pid_file "$sid")

    echo -e "${CYAN}[$sid]${NC} ${name}"
    echo -e "        Tunnel: localhost:${local_port} → ${oracle_host}:${oracle_port}"
    echo -e "        Via:    ${ssh_user}@${ssh_host}:${ssh_port}"

    if check_tunnel "$sid"; then
        echo -e "        ${YELLOW}⚠️  Already running (PID: $(cat $pid_file))${NC}"
        return 0
    fi

    # Prepare SSH key if exists
    local tmp_key="/tmp/ssh_key_${sid}"
    local use_key=false
    if [ -f "$ssh_key" ]; then
        cp "$ssh_key" "$tmp_key"
        chmod 600 "$tmp_key"
        use_key=true
    fi

    # Build SSH command
    local ssh_cmd="ssh -f -N -L ${local_port}:${oracle_host}:${oracle_port}"
    ssh_cmd+=" -p ${ssh_port}"
    ssh_cmd+=" -o StrictHostKeyChecking=no"
    ssh_cmd+=" -o ServerAliveInterval=60"
    ssh_cmd+=" -o ServerAliveCountMax=3"
    ssh_cmd+=" -o ExitOnForwardFailure=yes"

    if [ "$use_key" = true ]; then
        ssh_cmd+=" -i ${tmp_key}"
        ssh_cmd+=" ${ssh_user}@${ssh_host}"

        # Execute with key
        eval "$ssh_cmd" 2>/dev/null
    elif [ -n "$ssh_pass" ]; then
        # Use sshpass for password authentication
        if ! command -v sshpass &> /dev/null; then
            echo -e "        ${RED}❌ sshpass not installed (needed for password auth)${NC}"
            echo -e "        ${YELLOW}   Install: sudo apt install sshpass${NC}"
            return 1
        fi
        ssh_cmd+=" ${ssh_user}@${ssh_host}"
        sshpass -p "$ssh_pass" $ssh_cmd 2>/dev/null
    else
        echo -e "        ${RED}❌ No SSH key or password found${NC}"
        echo -e "        ${YELLOW}   Add: secrets/${sid}.ssh_key or secrets/${sid}.ssh_pass${NC}"
        return 1
    fi

    # Check if tunnel started
    sleep 1
    local tunnel_pid=$(pgrep -f "ssh.*-L ${local_port}:${oracle_host}:${oracle_port}" | head -1)

    if [ -n "$tunnel_pid" ]; then
        echo "$tunnel_pid" > "$pid_file"
        echo -e "        ${GREEN}✅ Started (PID: $tunnel_pid)${NC}"

        # Test connectivity
        if timeout 3 bash -c "cat < /dev/null > /dev/tcp/127.0.0.1/$local_port" 2>/dev/null; then
            echo -e "        ${GREEN}✅ Port $local_port accessible${NC}"
        else
            echo -e "        ${YELLOW}⚠️  Port $local_port not responding (Oracle may be down)${NC}"
        fi
        return 0
    else
        echo -e "        ${RED}❌ Failed to start tunnel${NC}"
        return 1
    fi
}

stop_single_tunnel() {
    local sid=$1
    local pid_file=$(get_pid_file "$sid")
    local name="${SERVER_NAMES[$sid]}"

    echo -e "${CYAN}[$sid]${NC} ${name}"

    if [ -f "$pid_file" ]; then
        local pid=$(cat "$pid_file")
        if ps -p "$pid" > /dev/null 2>&1; then
            kill "$pid" 2>/dev/null
            rm -f "$pid_file"
            echo -e "        ${GREEN}✅ Stopped (was PID: $pid)${NC}"
        else
            rm -f "$pid_file"
            echo -e "        ${YELLOW}⚠️  Was not running${NC}"
        fi
    else
        echo -e "        ${YELLOW}⚠️  Was not running${NC}"
    fi
}

status_single_tunnel() {
    local sid=$1
    local name="${SERVER_NAMES[$sid]}"
    local local_port="${LOCAL_PORTS[$sid]}"
    local pid_file=$(get_pid_file "$sid")

    if check_tunnel "$sid"; then
        local pid=$(cat "$pid_file")
        echo -e "${GREEN}●${NC} ${CYAN}[$sid]${NC} ${name}"
        echo -e "     localhost:${local_port} (PID: $pid)"

        if timeout 2 bash -c "cat < /dev/null > /dev/tcp/127.0.0.1/$local_port" 2>/dev/null; then
            echo -e "     ${GREEN}Port accessible${NC}"
        else
            echo -e "     ${YELLOW}Port not responding${NC}"
        fi
    else
        echo -e "${RED}○${NC} ${CYAN}[$sid]${NC} ${name}"
        echo -e "     localhost:${local_port} (stopped)"
    fi
}

# ============================================================================
# Main commands
# ============================================================================

print_header() {
    echo -e "${BLUE}════════════════════════════════════════════${NC}"
    echo -e "${BLUE}  ROA2WEB SSH Tunnel Manager (Multi-Server)${NC}"
    echo -e "${BLUE}════════════════════════════════════════════${NC}"
    echo
}

cmd_start() {
    print_header
    parse_config

    echo -e "${BLUE}Starting ${#SERVER_IDS[@]} tunnel(s)...${NC}"
    echo

    local failed=0
    for sid in "${SERVER_IDS[@]}"; do
        start_single_tunnel "$sid" || ((failed++))
        echo
    done

    if [ $failed -gt 0 ]; then
        echo -e "${YELLOW}⚠️  $failed tunnel(s) failed to start${NC}"
        return 1
    else
        echo -e "${GREEN}✅ All tunnels started successfully${NC}"
    fi
}

cmd_stop() {
    print_header
    parse_config

    echo -e "${BLUE}Stopping tunnels...${NC}"
    echo

    for sid in "${SERVER_IDS[@]}"; do
        stop_single_tunnel "$sid"
    done

    echo
    echo -e "${GREEN}✅ All tunnels stopped${NC}"
}

cmd_status() {
    print_header
    parse_config

    echo -e "${BLUE}Tunnel Status:${NC}"
    echo "────────────────────────────────────────────"

    for sid in "${SERVER_IDS[@]}"; do
        status_single_tunnel "$sid"
        echo
    done
}

cmd_restart() {
    cmd_stop
    sleep 2
    cmd_start
}

cmd_help() {
    print_header
    parse_config

    echo -e "${BLUE}Usage:${NC} $0 {start|stop|status|restart|help}"
    echo
    echo -e "${BLUE}Commands:${NC}"
    echo "  start    - Start all configured SSH tunnels"
    echo "  stop     - Stop all SSH tunnels"
    echo "  status   - Show status of all tunnels"
    echo "  restart  - Restart all tunnels"
    echo "  help     - Show this help"
    echo
    echo -e "${BLUE}Configuration:${NC}"
    echo "  SSH Tunnels: $SSH_TUNNELS_FILE"
    echo "  Secrets:     $SECRETS_DIR/"
    echo "  Fallback:    $ENV_FILE (legacy mode)"
    echo
    echo -e "${BLUE}Configured Tunnels (${#SERVER_IDS[@]}):${NC}"
    for sid in "${SERVER_IDS[@]}"; do
        echo "  - [$sid] ${SERVER_NAMES[$sid]}"
        echo "      localhost:${LOCAL_PORTS[$sid]} → ${ORACLE_HOSTS[$sid]}:${ORACLE_PORTS[$sid]}"
        echo "      via ${SSH_USERS[$sid]}@${SSH_HOSTS[$sid]}:${SSH_PORTS[$sid]}"
    done
    echo
    echo -e "${BLUE}Secrets Files (per server_id):${NC}"
    echo "  secrets/{id}.ssh_key   - SSH private key (preferred)"
    echo "  secrets/{id}.ssh_pass  - SSH password (fallback, needs sshpass)"
    echo
    echo -e "${BLUE}Example ssh-tunnels.json:${NC}"
    echo '  [{"id": "romfast", "name": "Romfast", "local_port": 1521,'
    echo '    "ssh_host": "roa.romfast.ro", "ssh_port": 22122, "ssh_user": "roa2web",'
    echo '    "oracle_host": "10.0.20.36", "oracle_port": 1521}]'
    echo
}

# ============================================================================
# Main
# ============================================================================

case "${1:-help}" in
    start)   cmd_start ;;
    stop)    cmd_stop ;;
    status)  cmd_status ;;
    restart) cmd_restart ;;
    help|--help|-h) cmd_help ;;
    *)
        echo -e "${RED}❌ Unknown command: $1${NC}"
        echo
        cmd_help
        exit 1
        ;;
esac
