#!/usr/bin/env bash
set -euo pipefail

# JellyShip Installer
# Usage: curl -sSL https://forgejo.brads.computer/brad/jellyship/raw/branch/main/install.sh | bash

JELLYSHIP_VERSION="${JELLYSHIP_VERSION:-main}"
INSTALL_DIR="/opt/jellyship"
DATA_DIR="/var/lib/jellyship"
CONFIG_DIR="/etc/jellyship"
MOUNT_PATH="/media/jellyship"
TMPFS_PATH="/tmp/jellyship"
TMPFS_SIZE="512M"
REPO_URL="https://forgejo.brads.computer/brad/jellyship.git"

# Parse flags
INSTALL_JELLYFIN=true
INSTALL_VPN=false
WEBHOOK_PORT=9821

while [[ $# -gt 0 ]]; do
  case "$1" in
    --no-jellyfin) INSTALL_JELLYFIN=false; shift ;;
    --vpn) INSTALL_VPN=true; shift ;;
    --port) WEBHOOK_PORT="$2"; shift 2 ;;
    --help)
      echo "JellyShip Installer"
      echo ""
      echo "Usage: install.sh [OPTIONS]"
      echo ""
      echo "Options:"
      echo "  --no-jellyfin    Skip Jellyfin installation"
      echo "  --vpn            Install and configure Speedify VPN"
      echo "  --port PORT      Webhook listener port (default: 9821)"
      echo "  --help           Show this help"
      exit 0
      ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

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

log()  { echo -e "${GREEN}[jellyship]${NC} $*"; }
warn() { echo -e "${YELLOW}[jellyship]${NC} $*"; }
err()  { echo -e "${RED}[jellyship]${NC} $*" >&2; }

# Check root
if [[ $EUID -ne 0 ]]; then
  err "This script must be run as root (or with sudo)"
  exit 1
fi

# Check Debian
if ! grep -qi 'debian\|ubuntu' /etc/os-release 2>/dev/null; then
  warn "This installer is designed for Debian/Ubuntu. Proceeding anyway..."
fi

log "Starting JellyShip installation..."

# ============================================================
# 1. System dependencies
# ============================================================
log "Installing system dependencies..."
apt-get update -qq
apt-get install -y -qq \
  git curl build-essential python3 \
  libfuse3-dev fuse3 \
  jq ca-certificates gnupg

# ============================================================
# 2. Node.js 22
# ============================================================
if ! command -v node &>/dev/null || [[ $(node -v | sed 's/v//' | cut -d. -f1) -lt 22 ]]; then
  log "Installing Node.js 22..."
  curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
  apt-get install -y -qq nodejs
else
  log "Node.js $(node -v) already installed"
fi

# ============================================================
# 3. Create jellyship user
# ============================================================
if ! id jellyship &>/dev/null; then
  log "Creating jellyship user..."
  useradd --system --create-home --shell /usr/sbin/nologin jellyship
fi

# ============================================================
# 4. Create directories
# ============================================================
log "Creating directories..."
mkdir -p "$INSTALL_DIR" "$DATA_DIR" "$CONFIG_DIR" "$MOUNT_PATH"
mkdir -p "$DATA_DIR/piece-cache" "$DATA_DIR/torrent-cache"
chown -R jellyship:jellyship "$DATA_DIR" "$MOUNT_PATH"

# Downloads directory (default torrent data path)
mkdir -p "$INSTALL_DIR/downloads"

# Create log file
touch /var/log/jellyship.log
chown jellyship:jellyship /var/log/jellyship.log

# ============================================================
# 5. FUSE permissions
# ============================================================
log "Configuring FUSE..."
if ! grep -q 'user_allow_other' /etc/fuse.conf 2>/dev/null; then
  echo 'user_allow_other' >> /etc/fuse.conf
fi

# ============================================================
# 6. WebTorrent tmpfs (in-memory torrent scratch space)
# ============================================================
log "Setting up tmpfs at $TMPFS_PATH ($TMPFS_SIZE)..."
mkdir -p "$TMPFS_PATH"
chown jellyship:jellyship "$TMPFS_PATH"

if ! grep -q "$TMPFS_PATH" /etc/fstab 2>/dev/null; then
  echo "tmpfs $TMPFS_PATH tmpfs size=$TMPFS_SIZE,mode=0755,uid=$(id -u jellyship),gid=$(id -g jellyship) 0 0" >> /etc/fstab
fi

if ! mountpoint -q "$TMPFS_PATH" 2>/dev/null; then
  mount "$TMPFS_PATH"
fi

# ============================================================
# 7. Clone and build
# ============================================================
log "Cloning JellyShip..."
if [[ -d "$INSTALL_DIR/.git" ]]; then
  cd "$INSTALL_DIR"
  git fetch origin
  git reset --hard "origin/$JELLYSHIP_VERSION"
else
  git clone --branch "$JELLYSHIP_VERSION" "$REPO_URL" "$INSTALL_DIR"
  cd "$INSTALL_DIR"
fi

log "Installing dependencies..."
# Full install (not --production) because esbuild is needed for build step
npm install

log "Building..."
npm run build

chown -R jellyship:jellyship "$INSTALL_DIR"

# ============================================================
# 8. Configuration
# ============================================================
if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then
  log "Installing default configuration..."
  cp configs/jellyship.default.yaml "$CONFIG_DIR/config.yaml"
  # Update mount path if customized
  sed -i "s|/media/jellyship|$MOUNT_PATH|g" "$CONFIG_DIR/config.yaml"
fi

# ============================================================
# 9. MaxMind GeoLite2 databases
# ============================================================
log "Note: GeoLite2 databases require a MaxMind account (free)"
log "Sign up at https://www.maxmind.com/en/geolite2/signup"
log "Then download GeoLite2-Country.mmdb and GeoLite2-ASN.mmdb to $DATA_DIR/"

# ============================================================
# 10. Jellyfin (optional) — install + auto-configure
# ============================================================
JELLYFIN_URL="http://localhost:8096"
JELLYFIN_USER="jellyship"
JELLYFIN_PASS="jellyship"
AUTH_HEADER_BASE='MediaBrowser Client="JellyShip", Device="Server", DeviceId="jellyship-installer", Version="1.0.0"'
WEBHOOK_PLUGIN_GUID="71552A5A-5C5C-4350-A2AE-EBE451A30173"

jf_curl() {
  local token_part=""
  if [[ -n "${ACCESS_TOKEN:-}" ]]; then
    token_part=", Token=\"$ACCESS_TOKEN\""
  fi
  curl -sS -H "Authorization: ${AUTH_HEADER_BASE}${token_part}" \
       -H "Content-Type: application/json" \
       "$@"
}

wait_for_jellyfin() {
  local max_attempts=60
  local attempt=0
  log "Waiting for Jellyfin to be ready..."
  while [[ $attempt -lt $max_attempts ]]; do
    local resp
    resp=$(curl -sf "$JELLYFIN_URL/System/Info/Public" 2>/dev/null || true)
    if [[ -n "$resp" ]] && echo "$resp" | jq -e '.Version' &>/dev/null; then
      sleep 3
      log "Jellyfin is ready!"
      return 0
    fi
    attempt=$((attempt + 1))
    sleep 2
  done
  err "Jellyfin did not become ready after $((max_attempts * 2)) seconds"
  return 1
}

jellyfin_authenticate() {
  log "Authenticating with Jellyfin as $JELLYFIN_USER..."
  local auth_response
  auth_response=$(jf_curl -X POST "$JELLYFIN_URL/Users/AuthenticateByName" \
    -d "{\"Username\":\"$JELLYFIN_USER\",\"Pw\":\"$JELLYFIN_PASS\"}")
  ACCESS_TOKEN=$(echo "$auth_response" | jq -r '.AccessToken // empty')
  if [[ -z "$ACCESS_TOKEN" ]]; then
    err "Failed to authenticate with Jellyfin"
    err "Response: $auth_response"
    return 1
  fi
  log "Authenticated successfully (token: ${ACCESS_TOKEN:0:8}...)"
}

if $INSTALL_JELLYFIN; then
  # --- Install Jellyfin if not present ---
  if ! dpkg -l jellyfin-server &>/dev/null 2>&1 && ! dpkg -l jellyfin &>/dev/null 2>&1; then
    log "Installing Jellyfin..."
    apt-get install -y -qq apt-transport-https
    curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg
    cat > /etc/apt/sources.list.d/jellyfin.list << JFEOF
deb [signed-by=/usr/share/keyrings/jellyfin.gpg arch=$(dpkg --print-architecture)] https://repo.jellyfin.org/debian $(. /etc/os-release && echo "$VERSION_CODENAME") main
JFEOF
    apt-get update -qq
    apt-get install -y -qq jellyfin
  else
    log "Jellyfin already installed"
  fi

  # Allow jellyfin to read JellyShip's FUSE mount
  usermod -aG jellyship jellyfin 2>/dev/null || true

  # Ensure Jellyfin is running
  systemctl enable jellyfin 2>/dev/null || true
  systemctl start jellyfin 2>/dev/null || true

  # Create media directories under FUSE mount point
  mkdir -p "$MOUNT_PATH/movies" "$MOUNT_PATH/tv"
  chown jellyship:jellyship "$MOUNT_PATH/movies" "$MOUNT_PATH/tv"
  chmod 775 "$MOUNT_PATH" "$MOUNT_PATH/movies" "$MOUNT_PATH/tv"

  # --- Wait for Jellyfin to be ready ---
  wait_for_jellyfin

  # --- Check if setup wizard is already completed ---
  ACCESS_TOKEN=""
  WIZARD_COMPLETED=false
  system_info=$(jf_curl "$JELLYFIN_URL/System/Info/Public" 2>/dev/null || true)
  if echo "$system_info" | jq -e '.StartupWizardCompleted == true' &>/dev/null; then
    WIZARD_COMPLETED=true
    log "Jellyfin setup wizard already completed — skipping wizard steps"
  fi

  # --------------------------------------------------------
  # Complete the setup wizard
  # --------------------------------------------------------
  if ! $WIZARD_COMPLETED; then
    log "Running Jellyfin setup wizard..."

    log "  → Initializing default user..."
    jf_curl "$JELLYFIN_URL/Startup/User" > /dev/null

    log "  → Setting language to en-US..."
    jf_curl -X POST "$JELLYFIN_URL/Startup/Configuration" \
      -d '{"UICulture":"en-US","MetadataCountryCode":"US","PreferredMetadataLanguage":"en"}' > /dev/null

    log "  → Creating admin user ($JELLYFIN_USER)..."
    jf_curl -X POST "$JELLYFIN_URL/Startup/User" \
      -d "{\"Name\":\"$JELLYFIN_USER\",\"Password\":\"$JELLYFIN_PASS\"}" > /dev/null

    log "  → Enabling remote access..."
    jf_curl -X POST "$JELLYFIN_URL/Startup/RemoteAccess" \
      -d '{"EnableRemoteAccess":true,"EnableAutomaticPortMapping":false}' > /dev/null

    log "  → Completing setup wizard..."
    jf_curl -X POST "$JELLYFIN_URL/Startup/Complete" > /dev/null

    log "Setup wizard completed!"
  fi

  # --------------------------------------------------------
  # Authenticate
  # --------------------------------------------------------
  jellyfin_authenticate

  # --------------------------------------------------------
  # Create media libraries
  # --------------------------------------------------------
  log "Configuring media libraries..."

  existing_libs=$(jf_curl "$JELLYFIN_URL/Library/VirtualFolders" 2>/dev/null || echo "[]")

  if ! echo "$existing_libs" | jq -e '.[] | select(.Name == "Movies")' &>/dev/null; then
    log "  → Creating Movies library..."
    jf_curl -X POST \
      "$JELLYFIN_URL/Library/VirtualFolders?name=Movies&collectionType=movies&refreshLibrary=false" \
      -d "{\"LibraryOptions\":{},\"PathInfos\":[{\"Path\":\"$MOUNT_PATH/movies\"}]}" > /dev/null
  else
    log "  → Movies library already exists"
  fi

  if ! echo "$existing_libs" | jq -e '.[] | select(.Name == "TV Shows")' &>/dev/null; then
    log "  → Creating TV Shows library..."
    jf_curl -X POST \
      "$JELLYFIN_URL/Library/VirtualFolders?name=TV%20Shows&collectionType=tvshows&refreshLibrary=false" \
      -d "{\"LibraryOptions\":{},\"PathInfos\":[{\"Path\":\"$MOUNT_PATH/tv\"}]}" > /dev/null
  else
    log "  → TV Shows library already exists"
  fi

  # --------------------------------------------------------
  # Install Webhook plugin
  # --------------------------------------------------------
  log "Installing Webhook plugin..."

  log "  → Adding Jellyfin plugin repository..."
  jf_curl -X POST "$JELLYFIN_URL/Repositories" \
    -d '[{"Name":"Jellyfin Stable","Url":"https://repo.jellyfin.org/files/plugin/manifest.json","Enabled":true}]' > /dev/null

  log "  → Installing Webhook plugin..."
  jf_curl -X POST \
    "$JELLYFIN_URL/Packages/Installed/Webhook?assemblyGuid=$WEBHOOK_PLUGIN_GUID" > /dev/null

  log "  → Restarting Jellyfin to load plugin..."
  jf_curl -X POST "$JELLYFIN_URL/System/Restart" > /dev/null || true
  sleep 5

  wait_for_jellyfin

  ACCESS_TOKEN=""
  jellyfin_authenticate

  # --------------------------------------------------------
  # Configure Webhook plugin
  # --------------------------------------------------------
  log "Configuring Webhook plugin..."

  WEBHOOK_CONFIG=$(cat <<'WEOF'
{
  "ServerUrl": "",
  "GenericOptions": [
    {
      "WebhookUri": "http://localhost:WEBHOOK_PORT_PLACEHOLDER/webhook",
      "WebhookName": "JellyShip",
      "SendAllProperties": true,
      "NotificationTypes": [
        {"Type": "PlaybackStart"},
        {"Type": "PlaybackProgress"},
        {"Type": "PlaybackStop"},
        {"Type": "ItemAdded"}
      ],
      "Headers": []
    }
  ]
}
WEOF
)
  WEBHOOK_CONFIG=$(echo "$WEBHOOK_CONFIG" | sed "s/WEBHOOK_PORT_PLACEHOLDER/$WEBHOOK_PORT/g")

  jf_curl -X POST \
    "$JELLYFIN_URL/Plugins/$WEBHOOK_PLUGIN_GUID/Configuration" \
    -d "$WEBHOOK_CONFIG" > /dev/null
  log "Webhook configured → http://localhost:$WEBHOOK_PORT/webhook"

  # --------------------------------------------------------
  # Create JellyShip API key
  # --------------------------------------------------------
  log "Creating JellyShip API key..."

  jf_curl -X POST "$JELLYFIN_URL/Auth/Keys?app=JellyShip" > /dev/null

  api_keys_response=$(jf_curl "$JELLYFIN_URL/Auth/Keys")
  JELLYFIN_API_KEY=$(echo "$api_keys_response" | jq -r '.Items[] | select(.AppName == "JellyShip") | .AccessToken' | tail -1)

  if [[ -n "$JELLYFIN_API_KEY" ]]; then
    log "API key created: ${JELLYFIN_API_KEY:0:8}..."

    if [[ -f "$CONFIG_DIR/config.yaml" ]]; then
      if grep -q '^jellyfin:' "$CONFIG_DIR/config.yaml"; then
        sed -i "s|^  apiKey:.*|  apiKey: \"$JELLYFIN_API_KEY\"|" "$CONFIG_DIR/config.yaml"
        sed -i "s|^  url:.*|  url: \"$JELLYFIN_URL\"|" "$CONFIG_DIR/config.yaml"
        log "Updated Jellyfin settings in $CONFIG_DIR/config.yaml"
      else
        cat >> "$CONFIG_DIR/config.yaml" << CFGEOF

jellyfin:
  url: "$JELLYFIN_URL"
  apiKey: "$JELLYFIN_API_KEY"
CFGEOF
        log "Added Jellyfin settings to $CONFIG_DIR/config.yaml"
      fi
    fi
  else
    warn "Could not retrieve API key — configure manually in $CONFIG_DIR/config.yaml"
  fi

  # --------------------------------------------------------
  # Install JellyShip Jellyfin plugin
  # --------------------------------------------------------
  JELLYSHIP_PLUGIN_DLL="$INSTALL_DIR/jellyfin-plugin/Jellyfin.Plugin.JellyShip/bin/Release/net8.0/Jellyfin.Plugin.JellyShip.dll"

  if command -v dotnet &>/dev/null; then
    log "Building JellyShip Jellyfin plugin..."
    cd "$INSTALL_DIR/jellyfin-plugin/Jellyfin.Plugin.JellyShip"
    dotnet build -c Release --nologo -v q
    cd "$INSTALL_DIR"
  fi

  if [[ -f "$JELLYSHIP_PLUGIN_DLL" ]]; then
    log "Installing JellyShip Jellyfin plugin..."
    PLUGIN_DIR="/var/lib/jellyfin/plugins/JellyShip"
    mkdir -p "$PLUGIN_DIR"
    cp "$JELLYSHIP_PLUGIN_DLL" "$PLUGIN_DIR/"

    cat > "$PLUGIN_DIR/meta.json" << METAEOF
{
  "category": "",
  "changelog": "",
  "description": "JellyShip integration plugin for Jellyfin",
  "guid": "d4e5f6a7-b8c9-0123-4567-89abcdef0123",
  "imageUrl": "",
  "name": "JellyShip",
  "overview": "JellyShip Jellyfin Plugin",
  "owner": "JellyShip",
  "status": "Active",
  "targetAbi": "10.9.0.0",
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "version": "1.0.0.0"
}
METAEOF

    chown -R jellyfin:jellyfin "$PLUGIN_DIR"

    log "  → Restarting Jellyfin to load JellyShip plugin..."
    jf_curl -X POST "$JELLYFIN_URL/System/Restart" > /dev/null || true
    sleep 5
    wait_for_jellyfin
    log "JellyShip Jellyfin plugin installed!"
  else
    log "No JellyShip Jellyfin plugin DLL found — skipping plugin install"
  fi
fi

# ============================================================
# 11. Speedify VPN (optional)
# ============================================================
if $INSTALL_VPN; then
  warn "Speedify VPN installation not yet automated."
  warn "Download from https://www.speedify.com/download/ and configure manually."
fi

# ============================================================
# 12. systemd service
# ============================================================
log "Installing systemd service..."
cp configs/jellyship.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable jellyship
systemctl start jellyship
sleep 2

# ============================================================
# 13. Logrotate
# ============================================================
log "Installing logrotate config..."
cp configs/jellyship.logrotate /etc/logrotate.d/jellyship

# ============================================================
# Done
# ============================================================
echo ""
log "============================================"
log "  JellyShip installed successfully!"
log "============================================"
echo ""
log "  Install dir:  $INSTALL_DIR"
log "  Data dir:     $DATA_DIR"
log "  Config:       $CONFIG_DIR/config.yaml"
log "  FUSE mount:   $MOUNT_PATH"
log "  tmpfs:        $TMPFS_PATH ($TMPFS_SIZE)"
log "  Webhook port: $WEBHOOK_PORT"
echo ""
log "  Start:   systemctl start jellyship"
log "  Status:  systemctl status jellyship"
log "  Logs:    journalctl -u jellyship -f"
log "  Logs:    tail -f /var/log/jellyship.log"
echo ""
if $INSTALL_JELLYFIN; then
  log "  ── Jellyfin ──────────────────────────────"
  log "  URL:       $JELLYFIN_URL"
  log "  Username:  $JELLYFIN_USER"
  log "  Password:  $JELLYFIN_PASS"
  if [[ -n "${JELLYFIN_API_KEY:-}" ]]; then
    log "  API Key:   $JELLYFIN_API_KEY"
  fi
  log "  Libraries: Movies ($MOUNT_PATH/movies)"
  log "             TV Shows ($MOUNT_PATH/tv)"
  log "  Webhook:   http://localhost:$WEBHOOK_PORT/webhook"
  echo ""
fi
log "  Edit config: nano $CONFIG_DIR/config.yaml"
log "  Then restart: systemctl restart jellyship"
echo ""
warn "Don't forget to download GeoLite2 databases for seed diversity scoring!"
