#!/bin/sh
# pb-init-v3.sh — idempotent PocketBase bootstrap for the v3 stack.
#
# Safe to re-run: existing collections and fields are silently skipped.
#
# Env vars (defaults match docker-compose.yml):
#   POCKETBASE_URL             http://pocketbase:8090
#   POCKETBASE_ADMIN_EMAIL     admin@libnovel.local
#   POCKETBASE_ADMIN_PASSWORD  changeme123

set -e

PB="${POCKETBASE_URL:-http://pocketbase:8090}"
EMAIL="${POCKETBASE_ADMIN_EMAIL:-admin@libnovel.local}"
PASS="${POCKETBASE_ADMIN_PASSWORD:-changeme123}"

log() { printf '[pb-init] %s\n' "$*"; }

# ── 0. Ensure dependencies ────────────────────────────────────────────────────
command -v curl    > /dev/null 2>&1 || apk add --no-cache curl    > /dev/null 2>&1
command -v python3 > /dev/null 2>&1 || apk add --no-cache python3 > /dev/null 2>&1

# ── 1. Wait for PocketBase ────────────────────────────────────────────────────
log "waiting for PocketBase..."
until curl -sf "$PB/api/health" > /dev/null 2>&1; do sleep 2; done
log "PocketBase ready"

# ── 2. Bootstrap superuser (first-run only) ───────────────────────────────────
LOCATION=$(curl -sf -o /dev/null -w "%{redirect_url}" "$PB/_/" 2>/dev/null || true)
if echo "$LOCATION" | grep -q "pbinstal/"; then
  TOKEN=$(echo "$LOCATION" | sed 's|.*pbinstal/||' | tr -d ' \r\n')
  curl -sf -X POST "$PB/api/collections/_superusers/records" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $TOKEN" \
    -d "{\"email\":\"$EMAIL\",\"password\":\"$PASS\",\"passwordConfirm\":\"$PASS\"}" \
    > /dev/null 2>&1 || true
  log "superuser created"
fi

# ── 3. Authenticate ───────────────────────────────────────────────────────────
AUTH=$(curl -sf -X POST "$PB/api/collections/_superusers/auth-with-password" \
  -H "Content-Type: application/json" \
  -d "{\"identity\":\"$EMAIL\",\"password\":\"$PASS\"}")
TOK=$(echo "$AUTH" | sed 's/.*"token":"\([^"]*\)".*/\1/')
[ -z "$TOK" ] || [ "$TOK" = "$AUTH" ] && { log "ERROR: auth failed"; exit 1; }
log "authenticated"

# ── Helpers ───────────────────────────────────────────────────────────────────

# create NAME BODY — POST collection; 400/422 = already exists, treated as ok.
create() {
  NAME="$1"; BODY="$2"
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "$PB/api/collections" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $TOK" \
    -d "$BODY")
  case "$STATUS" in
    200|201) log "created: $NAME" ;;
    400|422) log "exists (skip): $NAME" ;;
    *)       log "WARNING: $NAME returned $STATUS" ;;
  esac
}

# add_index COLLECTION INDEX_NAME SQL_EXPR
# Fetches current schema, adds index if absent by name, PATCHes collection.
add_index() {
  COLL="$1"; INAME="$2"; ISQL="$3"
  SCHEMA=$(curl -sf -H "Authorization: Bearer $TOK" "$PB/api/collections/$COLL" 2>/dev/null)
  PARSED=$(echo "$SCHEMA" | python3 -c "
import sys, json
d = json.load(sys.stdin)
indexes = d.get('indexes', [])
exists = any('$INAME' in idx for idx in indexes)
print('exists=' + str(exists))
print('id=' + d.get('id', ''))
if not exists:
    indexes.append('$ISQL')
    print('indexes=' + json.dumps(indexes))
" 2>/dev/null)
  if echo "$PARSED" | grep -q "^exists=True"; then
    log "index exists (skip): $COLL.$INAME"; return
  fi
  COLL_ID=$(echo "$PARSED" | grep "^id=" | sed 's/^id=//')
  [ -z "$COLL_ID" ] && { log "WARNING: cannot resolve id for $COLL"; return; }
  NEW_INDEXES=$(echo "$PARSED" | grep "^indexes=" | sed 's/^indexes=//')
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -X PATCH "$PB/api/collections/$COLL_ID" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $TOK" \
    -d "{\"indexes\":${NEW_INDEXES}}")
  case "$STATUS" in
    200|201) log "added index: $COLL.$INAME" ;;
    *)       log "WARNING: add_index $COLL.$INAME returned $STATUS" ;;
  esac
}

# add_field COLLECTION FIELD_NAME FIELD_TYPE
# Fetches current schema, appends field if absent, PATCHes collection.
# Requires python3 for safe JSON manipulation.
add_field() {
  COLL="$1"; FIELD="$2"; TYPE="$3"
  SCHEMA=$(curl -sf -H "Authorization: Bearer $TOK" "$PB/api/collections/$COLL" 2>/dev/null)
  # Check existence and extract collection id + fields via python3
  PARSED=$(echo "$SCHEMA" | python3 -c "
import sys, json
d = json.load(sys.stdin)
fields = d.get('fields', [])
exists = any(f.get('name') == '$FIELD' for f in fields)
print('exists=' + str(exists))
print('id=' + d.get('id', ''))
if not exists:
    fields.append({'name': '$FIELD', 'type': '$TYPE'})
    print('fields=' + json.dumps(fields))
" 2>/dev/null)
  if echo "$PARSED" | grep -q "^exists=True"; then
    log "field exists (skip): $COLL.$FIELD"; return
  fi
  COLL_ID=$(echo "$PARSED" | grep "^id=" | sed 's/^id=//')
  [ -z "$COLL_ID" ] && { log "WARNING: cannot resolve id for $COLL"; return; }
  NEW_FIELDS=$(echo "$PARSED" | grep "^fields=" | sed 's/^fields=//')
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -X PATCH "$PB/api/collections/$COLL_ID" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $TOK" \
    -d "{\"fields\":${NEW_FIELDS}}")
  case "$STATUS" in
    200|201) log "added field: $COLL.$FIELD ($TYPE)" ;;
    *)       log "WARNING: add_field $COLL.$FIELD returned $STATUS" ;;
  esac
}

# ── 4. Collections ────────────────────────────────────────────────────────────

create "books" '{
  "name":"books","type":"base","fields":[
    {"name":"slug",          "type":"text",   "required":true},
    {"name":"title",         "type":"text",   "required":true},
    {"name":"author",        "type":"text"},
    {"name":"cover",         "type":"text"},
    {"name":"status",        "type":"text"},
    {"name":"genres",        "type":"json"},
    {"name":"summary",       "type":"text"},
    {"name":"total_chapters","type":"number"},
    {"name":"source_url",    "type":"text"},
    {"name":"ranking",       "type":"number"},
    {"name":"meta_updated",  "type":"text"}
  ]}'

create "chapters_idx" '{
  "name":"chapters_idx","type":"base","fields":[
    {"name":"slug",    "type":"text",   "required":true},
    {"name":"number",  "type":"number", "required":true},
    {"name":"title",   "type":"text"},
    {"name":"created", "type":"date"}
  ]}'

create "ranking" '{
  "name":"ranking","type":"base","fields":[
    {"name":"rank",      "type":"number","required":true},
    {"name":"slug",      "type":"text",  "required":true},
    {"name":"title",     "type":"text"},
    {"name":"author",    "type":"text"},
    {"name":"cover",     "type":"text"},
    {"name":"status",    "type":"text"},
    {"name":"genres",    "type":"json"},
    {"name":"source_url","type":"text"}
  ]}'

create "progress" '{
  "name":"progress","type":"base","fields":[
    {"name":"session_id","type":"text",  "required":true},
    {"name":"slug",      "type":"text",  "required":true},
    {"name":"chapter",   "type":"number"},
    {"name":"user_id",   "type":"text"},
    {"name":"audio_time","type":"number"},
    {"name":"updated",   "type":"text"}
  ]}'

create "scraping_tasks" '{
  "name":"scraping_tasks","type":"base","fields":[
    {"name":"kind",             "type":"text"},
    {"name":"target_url",       "type":"text"},
    {"name":"from_chapter",     "type":"number"},
    {"name":"to_chapter",       "type":"number"},
    {"name":"worker_id",        "type":"text"},
    {"name":"status",           "type":"text","required":true},
    {"name":"books_found",      "type":"number"},
    {"name":"chapters_scraped", "type":"number"},
    {"name":"chapters_skipped", "type":"number"},
    {"name":"errors",           "type":"number"},
    {"name":"error_message",    "type":"text"},
    {"name":"started",          "type":"date"},
    {"name":"finished",         "type":"date"},
    {"name":"heartbeat_at",     "type":"date"}
  ]}'

create "audio_jobs" '{
  "name":"audio_jobs","type":"base","fields":[
    {"name":"cache_key",    "type":"text",  "required":true},
    {"name":"slug",         "type":"text",  "required":true},
    {"name":"chapter",      "type":"number","required":true},
    {"name":"voice",        "type":"text"},
    {"name":"worker_id",    "type":"text"},
    {"name":"status",       "type":"text",  "required":true},
    {"name":"error_message","type":"text"},
    {"name":"started",      "type":"date"},
    {"name":"finished",     "type":"date"},
    {"name":"heartbeat_at", "type":"date"}
  ]}'

create "app_users" '{
  "name":"app_users","type":"base","fields":[
    {"name":"username",              "type":"text","required":true},
    {"name":"password_hash",         "type":"text"},
    {"name":"role",                  "type":"text"},
    {"name":"avatar_url",            "type":"text"},
    {"name":"created",               "type":"text"},
    {"name":"email",                 "type":"text"},
    {"name":"email_verified",        "type":"bool"},
    {"name":"verification_token",    "type":"text"},
    {"name":"verification_token_exp","type":"text"},
    {"name":"oauth_provider",        "type":"text"},
    {"name":"oauth_id",              "type":"text"}
  ]}'

 create "user_sessions" '{
  "name":"user_sessions","type":"base","fields":[
    {"name":"user_id",            "type":"text","required":true},
    {"name":"session_id",         "type":"text","required":true},
    {"name":"user_agent",         "type":"text"},
    {"name":"ip",                 "type":"text"},
    {"name":"device_fingerprint", "type":"text"},
    {"name":"created_at",         "type":"text"},
    {"name":"last_seen",          "type":"text"}
  ]}'

create "user_library" '{
  "name":"user_library","type":"base","fields":[
    {"name":"session_id","type":"text","required":true},
    {"name":"user_id",  "type":"text"},
    {"name":"slug",     "type":"text","required":true},
    {"name":"saved_at", "type":"text"}
  ]}'

create "user_settings" '{
  "name":"user_settings","type":"base","fields":[
    {"name":"session_id",      "type":"text",  "required":true},
    {"name":"user_id",         "type":"text"},
    {"name":"auto_next",       "type":"bool"},
    {"name":"voice",           "type":"text"},
    {"name":"speed",           "type":"number"},
    {"name":"theme",           "type":"text"},
    {"name":"locale",          "type":"text"},
    {"name":"font_family",     "type":"text"},
    {"name":"font_size",       "type":"number"},
    {"name":"announce_chapter","type":"bool"},
    {"name":"updated",         "type":"text"}
  ]}'

create "user_subscriptions" '{
  "name":"user_subscriptions","type":"base","fields":[
    {"name":"follower_id","type":"text","required":true},
    {"name":"followee_id","type":"text","required":true},
    {"name":"created",   "type":"text"}
  ]}'

create "book_comments" '{
  "name":"book_comments","type":"base","fields":[
    {"name":"slug",     "type":"text","required":true},
    {"name":"user_id",  "type":"text"},
    {"name":"username", "type":"text"},
    {"name":"body",     "type":"text"},
    {"name":"upvotes",  "type":"number"},
    {"name":"downvotes","type":"number"},
    {"name":"parent_id","type":"text"},
    {"name":"created",  "type":"text"}
  ]}'

create "comment_votes" '{
  "name":"comment_votes","type":"base","fields":[
    {"name":"comment_id","type":"text","required":true},
    {"name":"user_id",  "type":"text"},
    {"name":"session_id","type":"text"},
    {"name":"vote",     "type":"text"}
  ]}'

create "translation_jobs" '{
  "name":"translation_jobs","type":"base","fields":[
    {"name":"cache_key",    "type":"text",  "required":true},
    {"name":"slug",         "type":"text",  "required":true},
    {"name":"chapter",      "type":"number","required":true},
    {"name":"lang",         "type":"text",  "required":true},
    {"name":"worker_id",    "type":"text"},
    {"name":"status",       "type":"text",  "required":true},
    {"name":"error_message","type":"text"},
    {"name":"started",      "type":"date"},
    {"name":"finished",     "type":"date"},
    {"name":"heartbeat_at", "type":"date"}
  ]}'

create "ai_jobs" '{
  "name":"ai_jobs","type":"base","fields":[
    {"name":"kind",          "type":"text",  "required":true},
    {"name":"slug",          "type":"text"},
    {"name":"status",        "type":"text",  "required":true},
    {"name":"from_item",     "type":"number"},
    {"name":"to_item",       "type":"number"},
    {"name":"items_done",    "type":"number"},
    {"name":"items_total",   "type":"number"},
    {"name":"model",         "type":"text"},
    {"name":"payload",       "type":"text"},
    {"name":"error_message", "type":"text"},
    {"name":"started",       "type":"date"},
    {"name":"finished",      "type":"date"},
    {"name":"heartbeat_at",  "type":"date"}
  ]}'

create "discovery_votes" '{
  "name":"discovery_votes","type":"base","fields":[
    {"name":"session_id","type":"text","required":true},
    {"name":"user_id",   "type":"text"},
    {"name":"slug",      "type":"text","required":true},
    {"name":"action",    "type":"text","required":true}
  ]}'

create "book_ratings" '{
  "name":"book_ratings","type":"base","fields":[
    {"name":"session_id","type":"text",  "required":true},
    {"name":"user_id",  "type":"text"},
    {"name":"slug",     "type":"text",   "required":true},
    {"name":"rating",   "type":"number", "required":true}
  ]}'

# ── 5. Field migrations (idempotent — adds fields missing from older installs) ─
add_field "scraping_tasks" "heartbeat_at"           "date"
add_field "audio_jobs"     "heartbeat_at"           "date"
add_field "progress"       "user_id"                "text"
add_field "progress"       "audio_time"             "number"
add_field "progress"       "updated"                "text"
add_field "books"          "meta_updated"           "text"
add_field "app_users"      "email"                  "text"
add_field "app_users"      "email_verified"         "bool"
add_field "app_users"      "verification_token"     "text"
add_field "app_users"      "verification_token_exp" "text"
add_field "app_users"      "oauth_provider"         "text"
add_field "app_users"      "oauth_id"               "text"
add_field "app_users"      "polar_customer_id"      "text"
add_field "app_users"      "polar_subscription_id"  "text"
add_field "user_library"   "shelf"                  "text"
add_field "user_sessions"  "device_fingerprint"     "text"
add_field "chapters_idx"   "created"                "date"
add_field "user_settings"  "theme"                  "text"
add_field "user_settings"  "locale"                 "text"
add_field "user_settings"  "font_family"            "text"
add_field "user_settings"  "font_size"              "number"
add_field "user_settings"  "announce_chapter"       "bool"

# ── 6. Indexes ────────────────────────────────────────────────────────────────
add_index "chapters_idx" "idx_chapters_idx_slug_number" \
  "CREATE UNIQUE INDEX idx_chapters_idx_slug_number ON chapters_idx (slug, number)"
add_index "chapters_idx" "idx_chapters_idx_created" \
  "CREATE INDEX idx_chapters_idx_created ON chapters_idx (created)"

log "done"
