import { randomUUID } from 'node:crypto';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { supabase } from '../../supabase.js';
import { listEntries } from '../../files.js';

// Daten-Schicht für den Dialog (Foren + Threads + Wortmeldungen).
// Alle DB-Zugriffe laufen über den Service-Client (umgeht RLS).

const SITE_DIR = process.env.SITE_DIR || '/site';
export const LIBRARY_SLUG = 'beitraege';

export async function profileFor(email) {
  try {
    const all = JSON.parse(await readFile(path.join(SITE_DIR, 'data', 'authors.json'), 'utf8'));
    return all[email] || null;
  } catch { return null; }
}

// Library-Beiträge als Threads in der Kategorie „Beiträge" spiegeln, damit man
// auf jeden Beitrag einen Dialog starten kann. Idempotent (upsert über key).
//
// Gedrosselt: Reads rufen das bei jedem Forum-Aufruf, aber der eigentliche
// Sync (DB + Filesystem-Walk + Upsert) läuft höchstens alle SYNC_TTL ms.
// `force: true` (z.B. nach Publish) überspringt die Drosselung.
const SYNC_TTL = 60_000;
let lastSync = 0;
export async function syncLibrary({ force = false } = {}) {
  if (!force && Date.now() - lastSync < SYNC_TTL) return;
  lastSync = Date.now();
  const { data: forum } = await supabase
    .from('forums').select('id').eq('slug', LIBRARY_SLUG).single();
  if (!forum) return;
  let entries = [];
  try { entries = (await listEntries()).filter((e) => e.kind === 'beitrag'); } catch { return; }
  if (!entries.length) return;
  const rows = entries.map((e) => ({
    forum_id: forum.id, key: e.url, title: e.title, url: e.url, kind: 'library',
  }));
  // Nicht title überschreiben? Doch — Titel kann sich ändern. user_id/locked bleiben.
  await supabase.from('threads').upsert(rows, { onConflict: 'key', ignoreDuplicates: false });
}

// Wortmeldungen pro Thread-Key aggregieren: { [key]: {count, last} }.
// Aggregiert in Postgres (View comment_stats) statt alle Zeilen zu laden.
async function commentStats() {
  const { data } = await supabase.from('comment_stats').select('thread,count,last');
  const map = {};
  for (const r of data || []) map[r.thread] = { count: r.count, last: r.last };
  return map;
}

// Alle Foren mit Thread-/Wortmeldungs-Zahl und letzter Aktivität.
export async function forumsWithCounts() {
  await syncLibrary();
  const [{ data: forums }, { data: threads }, stats] = await Promise.all([
    supabase.from('forums').select('*').order('sort'),
    supabase.from('threads').select('id,forum_id,key,deleted'),
    commentStats(),
  ]);
  const byForum = {};
  for (const t of threads || []) {
    if (t.deleted) continue;
    const f = byForum[t.forum_id] || (byForum[t.forum_id] = { threads: 0, posts: 0, last: '' });
    f.threads += 1;
    const s = stats[t.key];
    if (s) { f.posts += s.count; if (s.last > f.last) f.last = s.last; }
  }
  return (forums || []).map((f) => ({
    ...f,
    thread_count: byForum[f.id]?.threads || 0,
    post_count: byForum[f.id]?.posts || 0,
    last_at: byForum[f.id]?.last || null,
  }));
}

// Ein Forum samt seiner Threads (nach letzter Aktivität sortiert).
export async function forumWithThreads(slug) {
  const { data: forum } = await supabase.from('forums').select('*').eq('slug', slug).single();
  if (!forum) return null;
  if (forum.kind === 'library') await syncLibrary();
  const [{ data: threads }, stats] = await Promise.all([
    supabase.from('threads').select('*').eq('forum_id', forum.id).eq('deleted', false),
    commentStats(),
  ]);
  const list = (threads || []).map((t) => ({
    key: t.key, title: t.title, url: t.url, kind: t.kind, locked: t.locked,
    author_name: t.author_name, created_at: t.created_at,
    count: stats[t.key]?.count || 0, last: stats[t.key]?.last || t.created_at,
  })).sort((a, b) => (b.last || '').localeCompare(a.last || ''));
  return { forum, threads: list };
}

// Letzte Wortmeldungen über alles — für die linke Spalte der Übersicht.
export async function recentComments(limit = 20) {
  await syncLibrary();
  const [{ data: comments }, { data: threads }, { data: forums }] = await Promise.all([
    supabase.from('comments').select('id,thread,author_name,body,created_at')
      .eq('deleted', false).order('created_at', { ascending: false }).limit(limit),
    supabase.from('threads').select('key,title,url,forum_id,kind'),
    supabase.from('forums').select('id,slug,name'),
  ]);
  const tByKey = {}; for (const t of threads || []) tByKey[t.key] = t;
  const fById = {}; for (const f of forums || []) fById[f.id] = f;
  return (comments || []).map((c) => {
    const t = tByKey[c.thread];
    const f = t ? fById[t.forum_id] : null;
    return {
      id: c.id, body: c.body, author_name: c.author_name, created_at: c.created_at,
      thread_title: t?.title || c.thread,
      thread_url: t ? (t.kind === 'library' ? t.url : '/dialog/?thread=' + encodeURIComponent(c.thread)) : c.thread,
      forum_name: f?.name || null, forum_slug: f?.slug || null,
    };
  });
}

// Moderations-Überblick: letzte Wortmeldungen + alle Threads (zum Sperren/Löschen).
export async function recentForModeration() {
  const [comments, { data: threads }, { data: forums }] = await Promise.all([
    recentComments(50),
    supabase.from('threads').select('key,title,url,kind,forum_id,locked,deleted,author_name,created_at')
      .order('created_at', { ascending: false }),
    supabase.from('forums').select('id,name,slug'),
  ]);
  const fById = {}; for (const f of forums || []) fById[f.id] = f;
  const stats = await commentStats();
  const t = (threads || []).map((x) => ({
    key: x.key, title: x.title, url: x.url, kind: x.kind, locked: x.locked, deleted: x.deleted,
    author_name: x.author_name, created_at: x.created_at,
    forum_name: fById[x.forum_id]?.name || null,
    count: stats[x.key]?.count || 0,
  }));
  return { comments, threads: t };
}

// Neuen Thread in einem Forum anlegen (+ erste Wortmeldung). Gibt den Thread zurück.
export async function createThread({ forumId, forumSlug, title, body, user, email }) {
  let fid = forumId;
  if (!fid && forumSlug) {
    const { data: f } = await supabase.from('forums').select('id,kind').eq('slug', forumSlug).single();
    if (!f) return { error: 'Forum unbekannt' };
    if (f.kind === 'library') return { error: 'In Beiträge entstehen Threads automatisch' };
    fid = f.id;
  }
  if (!fid) return { error: 'Forum nötig' };
  if (!title || !title.trim()) return { error: 'Titel nötig' };
  if (!body || !body.trim()) return { error: 'Erster Beitrag nötig' };

  const prof = await profileFor(email);
  const name = prof?.name || email.split('@')[0];
  const key = 't/' + randomUUID();
  const { data: thread, error: e1 } = await supabase.from('threads').insert({
    forum_id: fid, key, title: title.trim(), url: '/dialog/?thread=' + encodeURIComponent(key),
    kind: 'forum', author_name: name, user_id: user.id,
  }).select('*').single();
  if (e1) return { error: e1.message };
  const { error: e2 } = await supabase.from('comments').insert({
    thread: key, user_id: user.id, author_name: name,
    author_avatar: prof?.avatar || null, body: body.trim(),
  });
  if (e2) return { error: e2.message };
  return { thread };
}

// Ist ein Thread gesperrt? (verhindert neue Wortmeldungen)
export async function threadLocked(key) {
  const { data } = await supabase.from('threads').select('locked').eq('key', key).single();
  return !!data?.locked;
}

// Thread-Metadaten für die Thread-Ansicht (Titel, Forum-Rücklink, Lock-Status).
export async function threadMeta(key) {
  const { data: t } = await supabase
    .from('threads').select('title,url,kind,locked,forum_id').eq('key', key).single();
  if (!t) return null;
  let forum = null;
  if (t.forum_id) {
    const { data: f } = await supabase.from('forums').select('slug,name').eq('id', t.forum_id).single();
    forum = f || null;
  }
  return { title: t.title, url: t.url, kind: t.kind, locked: !!t.locked, forum };
}
