#!/usr/bin/env bash
#
# migrate.sh — liest kver-original.db und erzeugt daraus eine frische kver.db
# mit dem aktuellen Go-Schema. Die Quelldatenbank wird nie verändert.
# Idempotent: kver.db wird bei jedem Lauf neu erstellt.
#
# Verwendung:
#   ./migrate.sh [quelldatei [zieldatei]]   # Standard: kver-original.db -> kver.db
#
# Schalter (als Umgebungsvariablen):
#   REPLIES=keep|drop   Antworten (reply_to != 0) übernehmen oder verwerfen (Default: keep)
#
set -euo pipefail

SRC="${1:-original-kver.db}"
DST="${2:-kver.db}"
REPLIES="${REPLIES:-keep}"

if [[ ! -f "$SRC" ]]; then
  echo "FEHLER: Quelldatenbank '$SRC' nicht gefunden." >&2
  exit 1
fi
if [[ "$REPLIES" != "keep" && "$REPLIES" != "drop" ]]; then
  echo "FEHLER: REPLIES muss 'keep' oder 'drop' sein (war: '$REPLIES')." >&2
  exit 1
fi
if [[ "$SRC" -ef "$DST" ]]; then
  echo "FEHLER: Quelle und Ziel sind dieselbe Datei." >&2
  exit 1
fi

qs() { sqlite3 "$SRC" "$1"; }
qd() { sqlite3 "$DST" "$1"; }

echo "== kver-Migration =="
echo "Quelle:  $SRC"
echo "Ziel:    $DST"
echo "REPLIES: $REPLIES"
echo

echo "Quelle:"
echo "  Einträge gesamt:        $(qs 'SELECT COUNT(*) FROM entry;')"
echo "  davon deleted=1:        $(qs 'SELECT COUNT(*) FROM entry WHERE deleted=1;')"
echo "  davon Antworten:        $(qs 'SELECT COUNT(*) FROM entry WHERE reply_to!=0;')"
echo "  User:                   $(qs 'SELECT COUNT(*) FROM user;')"

# Zieldatenbank immer frisch anlegen
rm -f "$DST"
echo
echo "Erstelle $DST mit aktuellem Schema..."

sqlite3 "$DST" <<'SCHEMA'
.bail on
CREATE TABLE user (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    uid        INTEGER UNIQUE,
    username   TEXT UNIQUE,
    password   BLOB,
    created_at INTEGER,
    last_login INTEGER,
    avatar     TEXT NOT NULL DEFAULT ''
);
CREATE TABLE session (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    uid         INTEGER,
    value       TEXT UNIQUE,
    created_at  INTEGER,
    expires     INTEGER,
    description TEXT
);
CREATE TABLE entry (
    id            INTEGER PRIMARY KEY AUTOINCREMENT,
    pid           INTEGER UNIQUE NOT NULL,
    uid           INTEGER NOT NULL,
    created_at    INTEGER NOT NULL,
    content       TEXT NOT NULL DEFAULT '',
    filepath      TEXT NOT NULL DEFAULT '',
    reply_to      INTEGER NOT NULL DEFAULT 0,
    reply_count   INTEGER NOT NULL DEFAULT 0,
    last_activity INTEGER NOT NULL DEFAULT 0,
    deleted       INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE vote (
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    uid  INTEGER,
    pid  INTEGER,
    mode TEXT,
    UNIQUE(uid, pid)
);
SCHEMA

# Prüfen, welche optionalen Spalten in der Quelle vorhanden sind.
# Ältere Python-DBs haben reply_count und last_activity noch nicht.
has_col() {
  sqlite3 "$SRC" "SELECT COUNT(*) FROM pragma_table_info('$1') WHERE name='$2';"
}

reply_count_expr="0"
[[ "$(has_col entry reply_count)" == "1" ]] && reply_count_expr="COALESCE(e.reply_count, 0)"

last_activity_expr="e.created_at"
[[ "$(has_col entry last_activity)" == "1" ]] && last_activity_expr="COALESCE(e.last_activity, e.created_at)"

# Profilbild: alte DBs haben die Spalte nicht -> leerer String.
avatar_expr="''"
[[ "$(has_col user avatar)" == "1" ]] && avatar_expr="COALESCE(u.avatar, '')"

replies_filter=""
[[ "$REPLIES" == "drop" ]] && replies_filter="AND e.reply_to = 0"

has_vote_table=$(qs "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='vote';")

# Quell-Pfad für SQL-String-Literal escapen (einfache Anführungszeichen verdoppeln)
src_sql="${SRC//\'/\'\'}"

sqlite3 "$DST" <<SQL
.bail on
ATTACH '$src_sql' AS src;
BEGIN;

-- User übernehmen; nur Spalten des aktuellen Schemas (Quelle kann Extra-Spalten haben)
INSERT INTO user (id, uid, username, password, created_at, last_login, avatar)
SELECT u.id, u.uid, u.username, u.password, u.created_at, u.last_login, $avatar_expr FROM src.user u;

-- Einträge transformieren:
--   filepath NULL und 'none' -> '' (Go-Zero-Value; scanEntries erwartet string, nicht *string)
--   content  NULL            -> ''
--   deleted: nur nicht-gelöschte Einträge werden übernommen
--   orphans: Einträge ohne bekannten User werden verworfen
INSERT INTO entry (pid, uid, created_at, content, filepath, reply_to, reply_count, last_activity, deleted)
SELECT
  e.pid,
  e.uid,
  e.created_at,
  COALESCE(e.content, ''),
  COALESCE(NULLIF(e.filepath, 'none'), ''),
  COALESCE(e.reply_to, 0),
  $reply_count_expr,
  $last_activity_expr,
  0
FROM src.entry e
WHERE e.deleted = 0
  AND e.uid IN (SELECT uid FROM src.user)
  $replies_filter;

-- Sessions leer lassen: Alt-Tokens sind Integer (Python-Format),
-- Go erzeugt crypto/rand-Hex-Tokens -> alle Alt-Sessions sind wertlos.

COMMIT;
DETACH src;
VACUUM;
SQL

# Votes separat, da die Tabelle in alten DBs fehlen kann
if [[ "$has_vote_table" == "1" ]]; then
  sqlite3 "$DST" <<SQL2
.bail on
ATTACH '$src_sql' AS src;
INSERT OR IGNORE INTO vote (uid, pid, mode)
SELECT uid, pid, mode FROM src.vote
WHERE uid IN (SELECT uid FROM entry)
  AND pid IN (SELECT pid FROM entry);
DETACH src;
SQL2
fi

echo
echo "Nachher:"
echo "  Einträge gesamt:        $(qd 'SELECT COUNT(*) FROM entry;')"
echo "  davon Antworten:        $(qd 'SELECT COUNT(*) FROM entry WHERE reply_to!=0;')"
echo "  sichtbar im Feed:       $(qd 'SELECT COUNT(*) FROM entry WHERE reply_to=0;')"
echo "  User:                   $(qd 'SELECT COUNT(*) FROM user;')"
echo "  Votes:                  $(qd 'SELECT COUNT(*) FROM vote;')"

# Medien-Check: referenzierte Bilder, die im Dateisystem fehlen
missing=0
total=0
while IFS= read -r fp; do
  [[ -z "$fp" ]] && continue
  total=$((total+1))
  [[ -f "$fp" ]] || missing=$((missing+1))
done < <(qd "SELECT filepath FROM entry WHERE filepath != '';")

echo
echo "Medien:"
echo "  referenziert:           $total"
echo "  fehlend im Dateisystem: $missing"
if [[ "$missing" -gt 0 ]]; then
  echo "  -> static/media/ aus der Produktion kopieren, sonst liefern diese Bilder 404."
fi

echo
echo "Fertig."
