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

BASE_DIR="/opt/app-update-check"
CONFIG_FILE="$BASE_DIR/apps.conf"
OUTPUT_FILE="$BASE_DIR/app-status.json"
TMP_FILE="$BASE_DIR/app-status.json.tmp"
GITHUB_API="https://api.github.com/repos"

[[ -f "$BASE_DIR/.env" ]] && source "$BASE_DIR/.env"

timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

names=()
types=()
urls=()
repos=()
extras=()
ssh_hosts=()
ssh_commands=()
auth_envs=()
tag_prefixes=()

section=""

trim() {
  local s="$1"
  s="${s#"${s%%[![:space:]]*}"}"
  s="${s%"${s##*[![:space:]]}"}"
  printf '%s' "$s"
}

while IFS= read -r line || [[ -n "$line" ]]; do
  line="${line%%#*}"
  line="$(trim "$line")"
  [[ -z "$line" ]] && continue

  if [[ "$line" =~ ^\[(.+)\]$ ]]; then
    section="${BASH_REMATCH[1]}"
    names+=("$section")
    types+=("")
    urls+=("")
    repos+=("")
    extras+=("")
    ssh_hosts+=("")
    ssh_commands+=("")
    auth_envs+=("")
    tag_prefixes+=("")
    continue
  fi

  key="${line%%=*}"
  value="${line#*=}"
  value="$(trim "$value")"
  value="${value%\"}"
  value="${value#\"}"

  last=$(( ${#names[@]} - 1 ))
  [[ $last -lt 0 ]] && continue

  case "$key" in
    type) types[$last]="$value" ;;
    url) urls[$last]="$value" ;;
    github_repo) repos[$last]="$value" ;;
    json_path|header_name) extras[$last]="$value" ;;
    ssh_host) ssh_hosts[$last]="$value" ;;
    command) ssh_commands[$last]="$value" ;;
    auth_env) auth_envs[$last]="$value" ;;
    tag_prefix) tag_prefixes[$last]="$value" ;;
  esac
done < "$CONFIG_FILE"

get_github_latest() {
  local repo="$1"
  local prefix="$2"

  local github_curl_args=()
  github_curl_args+=(--max-time 20)
  github_curl_args+=(-H "Accept: application/vnd.github+json")
  github_curl_args+=(-H "User-Agent: vermon-update-check")

  if [[ -n "${GITHUB_TOKEN:-}" ]]; then
    github_curl_args+=(-H "Authorization: Bearer ${GITHUB_TOKEN}")
  fi

  if [[ -n "$prefix" ]]; then
    git ls-remote --tags "https://github.com/$repo.git" "${prefix}*" 2>/dev/null |
      awk '{print $2}' |
      sed 's|refs/tags/||;s/\^{}$//' |
      sed -E "s/^${prefix//./\\.}//" |
      grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' |
      sort -V |
      tail -n1
  else
    curl -fsSL "${github_curl_args[@]}" \
      "$GITHUB_API/$repo/releases/latest" 2>/dev/null |
      jq -r '.tag_name // empty' |
      sed -E 's/^v//'
  fi
}

version_is_newer() {
  local installed="$1"
  local latest="$2"

  [[ -z "$installed" || -z "$latest" ]] && return 1
  [[ "$installed" == "$latest" ]] && return 1

  local lowest
  lowest=$(printf '%s\n%s\n' "$installed" "$latest" | sort -V | head -n1)

  [[ "$lowest" == "$installed" ]]
}

items=""

for i in "${!names[@]}"; do
  name="${names[$i]}"
  type="${types[$i]}"
  url="${urls[$i]}"
  repo="${repos[$i]}"
  extra="${extras[$i]}"
  ssh_host="${ssh_hosts[$i]}"
  remote_command="${ssh_commands[$i]}"
  auth_env="${auth_envs[$i]}"
  tag_prefix="${tag_prefixes[$i]}"

  installed=""
  latest=""
  status="ok"
  update_available="false"

  case "$type" in
    http_header)
      header_name="$extra"
      header_file=$(mktemp)

      curl_args=(
        -fsSL
        --max-time 20
        -D "$header_file"
        -o /dev/null
        "$url"
      )

      if [[ -n "$auth_env" ]]; then
        token_value="${!auth_env:-}"

        if [[ -n "$token_value" ]]; then
          curl_args+=(-H "Authorization: Token ${token_value}")
        else
          status="error"
        fi
      fi

      curl "${curl_args[@]}" 2>/dev/null

      installed=$(grep -i "^${header_name}:" "$header_file" 2>/dev/null |
        head -n1 |
        awk '{print $2}' |
        tr -d '\r')

      rm -f "$header_file"
      ;;

    json)
      curl_args=(--max-time 20)

      if [[ -n "${auth_env:-}" ]]; then
        token="${!auth_env:-}"

        if [[ -n "$token" ]]; then
          curl_args+=(-H "Authorization: Bearer ${token}")
        fi
      fi

      response=$(curl -fsSL "${curl_args[@]}" "$url" 2>/dev/null)
      installed=$(jq -r "$extra // empty" <<< "$response" 2>/dev/null)
      ;;

    json_composite)
      response=$(curl -fsSL --max-time 20 "$url" 2>/dev/null)

      major=$(jq -r '.major // empty' <<< "$response" 2>/dev/null)
      minor=$(jq -r '.minor // empty' <<< "$response" 2>/dev/null)
      patch=$(jq -r '.patch // empty' <<< "$response" 2>/dev/null)

      if [[ -n "$major" && -n "$minor" && -n "$patch" ]]; then
        installed="${major}.${minor}.${patch}"
      fi
      ;;

    ssh_command)
      if [[ -z "$ssh_host" || -z "$remote_command" ]]; then
        status="error"
      else
        installed=$(ssh \
          -o BatchMode=yes \
          -o ConnectTimeout=10 \
          -o StrictHostKeyChecking=accept-new \
          "root@${ssh_host}" \
          "$remote_command" 2>/dev/null |
          head -n1 |
          xargs)

        installed="${installed#v}"
      fi
      ;;

    pihole)
      password="${!auth_env:-}"

      if [[ -z "$password" ]]; then
        status="error"
      else
        auth_response=$(curl -fsSL --max-time 20 \
          -X POST "$url/api/auth" \
          -H "Content-Type: application/json" \
          -d "{\"password\":\"${password}\"}" 2>/dev/null)

        sid=$(jq -r '.session.sid // empty' <<< "$auth_response" 2>/dev/null)

        if [[ -n "$sid" ]]; then
          version_response=$(curl -fsSL --max-time 20 \
            -H "X-FTL-SID: ${sid}" \
            "$url/api/info/version" 2>/dev/null)

          core_local=$(jq -r '.version.core.local.version // empty' <<< "$version_response" 2>/dev/null)
          core_remote=$(jq -r '.version.core.remote.version // empty' <<< "$version_response" 2>/dev/null)
          web_local=$(jq -r '.version.web.local.version // empty' <<< "$version_response" 2>/dev/null)
          web_remote=$(jq -r '.version.web.remote.version // empty' <<< "$version_response" 2>/dev/null)
          ftl_local=$(jq -r '.version.ftl.local.version // empty' <<< "$version_response" 2>/dev/null)
          ftl_remote=$(jq -r '.version.ftl.remote.version // empty' <<< "$version_response" 2>/dev/null)

          installed="$core_local / $web_local / $ftl_local"

          if [[ -n "$core_remote" && -n "$web_remote" && -n "$ftl_remote" ]]; then
            latest="$core_remote / $web_remote / $ftl_remote"
            if [[ "$core_local" != "$core_remote" ]] ||
               [[ "$web_local" != "$web_remote" ]] ||
               [[ "$ftl_local" != "$ftl_remote" ]]; then
              update_available="true"
            fi
          else
            status="error"
          fi

          curl -fsSL --max-time 10 \
            -X DELETE \
            -H "X-FTL-SID: ${sid}" \
            "$url/api/auth" >/dev/null 2>&1
        else
          status="error"
        fi
      fi
      ;;

    *)
      status="error"
      ;;
  esac

  if [[ -z "$installed" || "$installed" == "null" ]]; then
    installed=""
    status="error"
  fi

  if [[ -n "$repo" ]]; then
    latest=$(get_github_latest "$repo" "$tag_prefix")
  fi

  if version_is_newer "$installed" "$latest"; then
    update_available="true"
  fi

  item=$(jq -n \
    --arg name "$name" \
    --arg installed "$installed" \
    --arg latest "$latest" \
    --arg status "$status" \
    --arg repo "$repo" \
    --argjson update "$update_available" \
    '{
      name: $name,
      installed: $installed,
      latest: $latest,
      status: $status,
      repo: $repo,
      updateAvailable: $update
    }')

  if [[ -z "$items" ]]; then
    items="$item"
  else
    items="$items,$item"
  fi
done

total_apps=${#names[@]}
apps_with_updates=$(echo "[$items]" | jq '[.[] | select(.updateAvailable == true)] | length')

jq -n \
  --arg generated "$timestamp" \
  --argjson totalApps "$total_apps" \
  --argjson appsWithUpdates "$apps_with_updates" \
  --argjson apps "[$items]" \
  '{
    generated: $generated,
    totalApps: $totalApps,
    appsWithUpdates: $appsWithUpdates,
    apps: $apps
  }' > "$TMP_FILE"

mv "$TMP_FILE" "$OUTPUT_FILE"

jq -r '
  "<!doctype html><html><head><meta charset=\"utf-8\"><title>App Updates</title>" +
  "<style>body{font-family:system-ui,sans-serif;background:#111827;color:#e5e7eb;margin:0;padding:16px}" +
  "h1{font-size:18px;margin:0 0 12px}ul{list-style:none;margin:0;padding:0}" +
  "li{display:flex;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;background:#1f2937;margin-bottom:6px}" +
  ".name{font-weight:600}.versions{color:#9ca3af;font-size:13px}</style></head><body>" +
  "<h1>Updates verfügbar</h1><ul>" +
  ([.apps[] | select(.updateAvailable == true) |
    "<li><span class=\"name\">" + .name + "</span><span class=\"versions\">" +
    .installed + " → " + .latest + "</span></li>"] | join("")) +
  "</ul></body></html>"
' "$OUTPUT_FILE" > "$BASE_DIR/updates.html"

jq '{totalUpdates: ([.apps[] | select(.updateAvailable == true)] | length), updates: ([.apps[] | select(.updateAvailable == true) | .name] | join(", "))}' "$OUTPUT_FILE" > "$BASE_DIR/updates-summary.json"


chmod 644 "$OUTPUT_FILE"

echo "Apps geprüft: $total_apps"
echo "Updates verfügbar: $apps_with_updates"
jq -r '.apps[] | "\(.name): \(.installed // "unbekannt") -> \(.latest // "unbekannt") | Update: \(.updateAvailable)"' "$OUTPUT_FILE"
