#!/usr/bin/env bash
# OpenFUT Setup Script
# Builds, configures, and starts the OpenFUT offline FUT emulator for FIFA 23.
# Run as a regular user; the script will sudo only for hosts/cert/iptables steps.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CORE_DIR="$SCRIPT_DIR/openfut-core"
BRIDGE_DIR="$SCRIPT_DIR/openfut-bridge"

CORE_PORT="${CORE_PORT:-8080}"
BRIDGE_PORT="${BRIDGE_PORT:-8443}"   # internal port; iptables forwards 443 → this
TLS_ENABLED="${TLS_ENABLED:-true}"

CORE_PID_FILE="/tmp/openfut-core.pid"
BRIDGE_PID_FILE="/tmp/openfut-bridge.pid"
CORE_LOG="/tmp/openfut-core.log"
BRIDGE_LOG="/tmp/openfut-bridge.log"

# EA FUT domains to redirect.
# Run './setup.sh watch-domains' while starting FIFA 23 to discover additional domains.
EA_HOSTS=(
    # Core FUT API
    "fut.ea.com"
    "utas.mob.v4.fut.ea.com"
    # EA account / auth
    "accounts.ea.com"
    "signin.ea.com"
    "gateway.ea.com"
    # Origin / EA Desktop API
    "api1.origin.com"
    "api2.origin.com"
    "api3.origin.com"
    # Telemetry / assets (can safely be silenced)
    "eas.ea.com"
    "eaassets-a.akamaihd.net"
    "eaassets-b.akamaihd.net"
)
HOSTS_MARKER="# OpenFUT — managed block (do not edit manually)"

# ── Colours ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'

info()    { echo -e "${CYAN}[INFO]${RESET}  $*"; }
ok()      { echo -e "${GREEN}[OK]${RESET}    $*"; }
warn()    { echo -e "${YELLOW}[WARN]${RESET}  $*"; }
error()   { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
heading() { echo -e "\n${BOLD}$*${RESET}"; }

# ── Helpers ────────────────────────────────────────────────────────────────────
require_cmd() {
    command -v "$1" &>/dev/null || { error "Required command not found: $1"; exit 1; }
}

is_running() {
    local pid_file="$1"
    [[ -f "$pid_file" ]] && kill -0 "$(cat "$pid_file")" 2>/dev/null
}

stop_service() {
    local pid_file="$1" name="$2"
    if is_running "$pid_file"; then
        kill "$(cat "$pid_file")" 2>/dev/null && ok "Stopped $name"
        rm -f "$pid_file"
    else
        warn "$name is not running"
    fi
}

# ── Commands ───────────────────────────────────────────────────────────────────

cmd_build() {
    heading "Building OpenFUT Core and Bridge…"
    require_cmd cargo

    info "Building Core (release)…"
    cargo build --release --manifest-path "$CORE_DIR/Cargo.toml" \
        2>&1 | grep -E "^(error|warning\[)" || true
    ok "Core built"

    info "Building Bridge (release)…"
    cargo build --release --manifest-path "$BRIDGE_DIR/Cargo.toml" \
        2>&1 | grep -E "^(error|warning\[)" || true
    ok "Bridge built"
}

cmd_start() {
    heading "Starting OpenFUT services…"

    # ── Core ──
    if is_running "$CORE_PID_FILE"; then
        warn "Core is already running (PID $(cat "$CORE_PID_FILE"))"
    else
        # Run from CORE_DIR so the default sqlite://openfut.db relative path works
        (
            cd "$CORE_DIR"
            LISTEN_ADDR="127.0.0.1:$CORE_PORT" \
            DATA_DIR="$CORE_DIR/data" \
                "$CORE_DIR/target/release/openfut-core" \
                >"$CORE_LOG" 2>&1
        ) &
        echo $! > "$CORE_PID_FILE"
        ok "Core started (PID $!) → http://127.0.0.1:$CORE_PORT  log: $CORE_LOG"
    fi

    # Give Core a moment to bind before Bridge starts
    sleep 1

    # ── Bridge ──
    if is_running "$BRIDGE_PID_FILE"; then
        warn "Bridge is already running (PID $(cat "$BRIDGE_PID_FILE"))"
    else
        BRIDGE_LISTEN_ADDR="0.0.0.0:$BRIDGE_PORT" \
        CORE_URL="http://127.0.0.1:$CORE_PORT" \
        TLS_ENABLED="$TLS_ENABLED" \
        PLACEHOLDER_MODE="true" \
        CAPTURES_DIR="$BRIDGE_DIR/captures" \
            "$BRIDGE_DIR/target/release/openfut-bridge" \
            >"$BRIDGE_LOG" 2>&1 &
        echo $! > "$BRIDGE_PID_FILE"
        local scheme="http"; [[ "$TLS_ENABLED" == "true" ]] && scheme="https"
        ok "Bridge started (PID $!) → ${scheme}://0.0.0.0:$BRIDGE_PORT  log: $BRIDGE_LOG"
    fi

    echo
    info "Dashboard:  http://127.0.0.1:$CORE_PORT/_bridge/dashboard  (via bridge: https://127.0.0.1:$BRIDGE_PORT/_bridge/dashboard)"
    info "Admin:      https://127.0.0.1:$BRIDGE_PORT/_bridge/admin"
    info "Setup guide: https://127.0.0.1:$BRIDGE_PORT/_bridge/guide"
}

cmd_stop() {
    heading "Stopping OpenFUT services…"
    stop_service "$BRIDGE_PID_FILE" "Bridge"
    stop_service "$CORE_PID_FILE"   "Core"
    cmd_unhosts
    cmd_unnat
}

cmd_status() {
    heading "OpenFUT service status"
    if is_running "$CORE_PID_FILE"; then
        ok "Core   is RUNNING (PID $(cat "$CORE_PID_FILE"))"
    else
        warn "Core   is STOPPED"
    fi
    if is_running "$BRIDGE_PID_FILE"; then
        ok "Bridge is RUNNING (PID $(cat "$BRIDGE_PID_FILE"))"
    else
        warn "Bridge is STOPPED"
    fi

    echo
    if grep -q "$HOSTS_MARKER" /etc/hosts 2>/dev/null; then
        ok "Hosts  entries are IN PLACE"
    else
        warn "Hosts  entries are NOT configured (run: ./setup.sh hosts)"
    fi

    if sudo iptables -t nat -L OUTPUT -n -v 2>/dev/null | grep -q "redir ports $BRIDGE_PORT"; then
        ok "NAT    redirect 127.0.0.1:443→$BRIDGE_PORT is ACTIVE"
    else
        warn "NAT    redirect is NOT active (run: ./setup.sh nat)"
    fi
}

cmd_logs() {
    heading "Tailing logs (Ctrl-C to stop)…"
    tail -f "$CORE_LOG" "$BRIDGE_LOG" 2>/dev/null || warn "No log files yet — start the services first."
}

cmd_hosts() {
    heading "Adding EA FUT hosts entries…"
    if grep -q "$HOSTS_MARKER" /etc/hosts 2>/dev/null; then
        ok "Hosts entries already present — skipping"
        return
    fi

    local block
    block="\n$HOSTS_MARKER\n"
    for host in "${EA_HOSTS[@]}"; do
        block+="127.0.0.1  $host\n"
    done
    block+="# end OpenFUT\n"

    echo -e "$block" | sudo tee -a /etc/hosts > /dev/null
    ok "Added to /etc/hosts:"
    for host in "${EA_HOSTS[@]}"; do
        echo "    127.0.0.1  $host"
    done
    info "Flush DNS if needed: sudo resolvectl flush-caches  (or: sudo systemd-resolve --flush-caches)"
}

cmd_unhosts() {
    if grep -q "$HOSTS_MARKER" /etc/hosts 2>/dev/null; then
        sudo sed -i "/^$HOSTS_MARKER/,/^# end OpenFUT/d" /etc/hosts
        ok "Removed OpenFUT hosts entries"
    fi
}

cmd_nat() {
    heading "Setting up iptables redirect 443 → $BRIDGE_PORT…"
    if sudo iptables -t nat -L OUTPUT -n 2>/dev/null | grep -q "redir ports $BRIDGE_PORT"; then
        ok "NAT rule already active"
        return
    fi
    # Scope to 127.0.0.1 only — /etc/hosts resolves EA domains to loopback, so
    # only those connections match. All real internet traffic goes to non-loopback
    # IPs and is never redirected.
    sudo iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 443 -j REDIRECT --to-port "$BRIDGE_PORT"
    ok "iptables: OUTPUT 127.0.0.1:443 → $BRIDGE_PORT"
    warn "This rule is NOT persistent across reboots. Re-run './setup.sh nat' after reboot or use iptables-save."
}

cmd_unnat() {
    if sudo iptables -t nat -L OUTPUT -n 2>/dev/null | grep -q "redir ports $BRIDGE_PORT"; then
        sudo iptables -t nat -D OUTPUT -p tcp -d 127.0.0.1 --dport 443 -j REDIRECT --to-port "$BRIDGE_PORT"
        ok "Removed iptables NAT rule"
    fi
}

cmd_cert() {
    heading "Installing TLS certificate…"

    local scheme="https"
    local cert_url="${scheme}://127.0.0.1:$BRIDGE_PORT/_bridge/cert.pem"
    local cert_dest="/tmp/openfut-ca.pem"

    if ! is_running "$BRIDGE_PID_FILE"; then
        error "Bridge is not running. Start it first with './setup.sh start'"
        exit 1
    fi

    info "Downloading certificate from $cert_url …"
    curl -sk "$cert_url" -o "$cert_dest" || { error "Failed to download cert. Is the Bridge running with TLS_ENABLED=true?"; exit 1; }

    if [[ ! -s "$cert_dest" ]]; then
        error "Downloaded cert is empty."
        exit 1
    fi

    ok "Certificate saved to $cert_dest"

    # Detect distro cert store
    if command -v update-ca-trust &>/dev/null; then
        # Arch / Fedora / RHEL
        sudo cp "$cert_dest" /etc/ca-certificates/trust-source/anchors/openfut-ca.pem
        sudo update-ca-trust
        ok "Certificate installed (update-ca-trust)"
    elif command -v update-ca-certificates &>/dev/null; then
        # Debian / Ubuntu
        sudo cp "$cert_dest" /usr/local/share/ca-certificates/openfut-ca.crt
        sudo update-ca-certificates
        ok "Certificate installed (update-ca-certificates)"
    else
        warn "Cannot auto-install cert — manual steps:"
        echo "  Copy $cert_dest to your system's trusted CA store."
    fi

    info "If using Steam/Proton, you may also need to add it to the game's certificate store."
    info "Wine cert path (Proton): WINEDEBUG=-all wine certutil -addstore Root $cert_dest"
}

cmd_proton_cert() {
    heading "Installing certificate into Proton / Wine (for Steam FIFA 23)…"

    local cert_dest="/tmp/openfut-ca.pem"
    if [[ ! -f "$cert_dest" ]]; then
        error "No cert found at $cert_dest — run './setup.sh cert' first"
        exit 1
    fi

    # Find Proton wine binary
    local proton_wine
    proton_wine=$(find "$HOME/.steam/steam/steamapps/common" -name "wine" -path "*/Proton*/wine" 2>/dev/null | head -1)

    if [[ -z "$proton_wine" ]]; then
        warn "Could not auto-detect Proton wine binary."
        echo "  Manually run:  wine certutil -addstore Root $cert_dest"
        echo "  with the correct WINEPREFIX for FIFA 23."
        return
    fi

    # Find FIFA 23 Proton prefix
    local steam_id_fifa23="1811260"
    local prefix="$HOME/.steam/steam/steamapps/compatdata/$steam_id_fifa23/pfx"

    if [[ ! -d "$prefix" ]]; then
        warn "FIFA 23 Proton prefix not found at $prefix"
        echo "  Launch FIFA 23 at least once to create the prefix, then re-run this step."
        return
    fi

    WINEPREFIX="$prefix" WINEDEBUG=-all "$proton_wine" certutil -addstore Root "$cert_dest" \
        && ok "Certificate added to FIFA 23 Proton prefix" \
        || warn "certutil failed — you may need to add it manually."
}

cmd_quickstart() {
    heading "OpenFUT Quick Start"
    echo "This will: build → start services → add hosts entries → set up NAT → install cert"
    echo
    read -rp "Continue? [y/N] " confirm
    [[ "${confirm,,}" == "y" ]] || { info "Aborted."; exit 0; }

    cmd_build
    cmd_start

    info "Waiting for services to initialise…"
    sleep 3

    # Verify Core is actually up before proceeding
    if ! is_running "$CORE_PID_FILE"; then
        error "Core failed to start. Check the log:"
        tail -20 "$CORE_LOG"
        exit 1
    fi
    if ! is_running "$BRIDGE_PID_FILE"; then
        error "Bridge failed to start. Check the log:"
        tail -20 "$BRIDGE_LOG"
        exit 1
    fi

    # sudo-gated steps — try them, print manual instructions if sudo not available
    echo
    heading "System configuration (requires sudo)…"

    if sudo -n true 2>/dev/null; then
        cmd_hosts
        cmd_nat
        sleep 1
        cmd_cert
        cmd_proton_cert
    else
        warn "Cannot acquire sudo non-interactively. Run these steps yourself:"
        echo
        echo "  1.  sudo ./setup.sh hosts"
        echo "  2.  sudo ./setup.sh nat"
        echo "  3.  ./setup.sh cert       (after the above two)"
        echo "  4.  ./setup.sh proton-cert"
    fi

    echo
    heading "Setup complete!"
    ok "FIFA 23 FUT traffic will now route to OpenFUT."
    echo
    echo -e "  Dashboard:   ${CYAN}http://127.0.0.1:$CORE_PORT/_bridge/dashboard${RESET}"
    echo -e "  Admin panel: ${CYAN}https://127.0.0.1:$BRIDGE_PORT/_bridge/admin${RESET}"
    echo -e "  Logs:        ${CYAN}./setup.sh logs${RESET}"
    echo -e "  Stop all:    ${CYAN}./setup.sh stop${RESET}"
}

cmd_watch_domains() {
    heading "Watching for unknown EA domains (Ctrl-C to stop)…"
    if ! is_running "$BRIDGE_PID_FILE"; then
        warn "Bridge is not running. Start it first with './setup.sh start'"
        exit 1
    fi
    info "Launch FIFA 23 now. Any domain that reaches the real EA servers will appear here."
    echo
    # Watch the bridge log for lines that contain host/domain info not already in our list
    tail -f "$BRIDGE_LOG" 2>/dev/null | grep --line-buffered -i "unknown\|placeholder\|host\|domain\|CONNECT" \
        | grep -v --line-buffered "$(IFS='|'; echo "${EA_HOSTS[*]}")" \
        | while IFS= read -r line; do
            echo -e "${YELLOW}$(date +'%H:%M:%S')${RESET}  $line"
        done
}

cmd_help() {
    cat <<EOF

${BOLD}OpenFUT Setup Script${RESET}
Offline FIFA 23 FUT emulator — for legitimate game owners only.

${BOLD}Usage:${RESET}  ./setup.sh <command>

${BOLD}Commands:${RESET}
  quickstart      Full setup in one step (build + start + hosts + nat + cert)
  build           Compile Core and Bridge in release mode
  start           Start Core and Bridge in the background
  stop            Stop both services and clean up hosts/NAT
  restart         Stop then start
  status          Show running state, hosts, and NAT status
  logs            Tail live logs from both services
  watch-domains   Show unknown EA domains hitting the bridge (add them to hosts)

  hosts           Add EA FUT domains to /etc/hosts (requires sudo)
  unhosts         Remove OpenFUT entries from /etc/hosts
  nat             Add iptables redirect 443 → $BRIDGE_PORT (requires sudo)
  unnat           Remove iptables NAT rule

  cert            Download TLS cert from Bridge and install system-wide
  proton-cert     Install TLS cert into the FIFA 23 Proton/Wine prefix

${BOLD}Environment overrides:${RESET}
  CORE_PORT       Core listen port         (default: 8080)
  BRIDGE_PORT     Bridge internal port     (default: 8443)
  TLS_ENABLED     Enable HTTPS on Bridge   (default: true)

${BOLD}Example:${RESET}
  ./setup.sh quickstart          # first-time full setup
  ./setup.sh start               # start after a reboot
  ./setup.sh stop                # clean shutdown

EOF
}

# ── Dispatch ───────────────────────────────────────────────────────────────────
case "${1:-help}" in
    quickstart)   cmd_quickstart ;;
    build)        cmd_build ;;
    start)        cmd_start ;;
    stop)         cmd_stop ;;
    restart)      cmd_stop; cmd_start ;;
    status)       cmd_status ;;
    logs)         cmd_logs ;;
    hosts)        cmd_hosts ;;
    unhosts)      cmd_unhosts ;;
    nat)          cmd_nat ;;
    unnat)        cmd_unnat ;;
    cert)         cmd_cert ;;
    proton-cert)  cmd_proton_cert ;;
    watch-domains) cmd_watch_domains ;;
    help|--help|-h) cmd_help ;;
    *)            error "Unknown command: $1"; cmd_help; exit 1 ;;
esac
