import { serve } from '@hono/node-server';
import { serveStatic } from '@hono/node-server/serve-static';
import { Hono } from 'hono';
import { secureHeaders } from 'hono/secure-headers';
import { bodyLimit } from 'hono/body-limit';

import { rateLimit } from './ratelimit.js';
import content from './routes/content.js';
import preview from './routes/preview.js';
import publish from './routes/publish.js';
import upload from './routes/upload.js';
import profile from './routes/profile.js';
import users from './routes/users.js';
import stats from './routes/stats.js';
import { listComments, createComment, deleteComment, login } from './routes/comments.js';
import history from './routes/history.js';
import {
  listForums, showForum, recent, threadInfo, newThread, mod, adminForums,
} from './routes/dialog.js';
import { requireAuth } from './auth.js';
import { syncLibrary } from './dialog-store.js';

const SITE_DIR = process.env.SITE_DIR || '/site';
const ADMIN_DIR = process.env.ADMIN_DIR || '/app/admin-dist';
const PORT = Number(process.env.PORT || 3000);

const app = new Hono();

// --- Sicherheits-Header (auf allem) ---
// CSP bewusst zurückhaltend: Site + Admin-SPA + Dialog-Widget laufen same-origin.
app.use('*', secureHeaders({
  xFrameOptions: 'SAMEORIGIN',
  xContentTypeOptions: 'nosniff',
  referrerPolicy: 'strict-origin-when-cross-origin',
  crossOriginOpenerPolicy: 'same-origin',
  // HSTS nur sinnvoll hinter TLS-Proxy; schadet via HTTP nicht (Browser ignoriert).
  strictTransportSecurity: 'max-age=31536000; includeSubDomains',
}));

// Hochgeladene Bilder strikt isolieren: ein bösartiges SVG kann so kein
// JavaScript im Origin ausführen (sandbox + keine Skript-Quellen).
app.use('/images/*', secureHeaders({
  contentSecurityPolicy: { defaultSrc: ["'none'"], imgSrc: ["'self'"], styleSrc: ["'unsafe-inline'"], sandbox: [] },
  xContentTypeOptions: 'nosniff',
}));

// Statische Assets cachen: Hugo fingerprintet CSS/JS, Uploads haben stabile,
// eindeutige Namen. HTML bleibt ungecacht (Antwort ohne Header → immer frisch).
app.use('*', async (c, next) => {
  await next();
  if (c.req.method === 'GET' && /\.(css|js|mjs|woff2?|ttf|otf|eot|svg|png|jpe?g|webp|avif|gif|ico)$/i.test(c.req.path)) {
    c.header('Cache-Control', 'public, max-age=604800');   // 1 Woche
  }
});

// --- API ---
// Globales Limit gegen aufgeblähte JSON-Bodies (DoS / DB-Bloat). Der Upload-Pfad
// ist ausgenommen — der bringt sein eigenes, größeres Bild-Limit mit.
const jsonBodyLimit = bodyLimit({ maxSize: 256 * 1024, onError: (c) => c.json({ error: 'Anfrage zu groß' }, 413) });
app.use('/api/*', (c, next) =>
  c.req.path.startsWith('/api/upload') ? next() : jsonBodyLimit(c, next));

app.get('/api/health', (c) => c.json({ ok: true, hugo: '0.161.1+extended' }));
// Öffentlich (ohne Login): Dialog lesen, Übersicht, Login fürs Dialog-Widget.
app.get('/api/comments', listComments);
app.get('/api/forums', listForums);
app.get('/api/forums/:slug', showForum);
app.get('/api/recent', recent);
app.get('/api/thread', threadInfo);
// Öffentlich: Versionsverlauf der Beiträge (Git-History) — auf der Site anzeigbar.
app.route('/api/history', history);
// Login gegen Brute-Force drosseln: max. 10 Versuche/IP pro 5 Minuten.
app.post('/api/auth/login', rateLimit({ max: 10, windowMs: 5 * 60_000 }), login);
// Alles weitere unter /api/* braucht ein gültiges Supabase-Token.
app.use('/api/*', requireAuth);
// Schreibzugriffe drosseln (Spam-Schutz, auch bei gekapertem Token):
// 60 Mutationen/Minute je Nutzer. Lesen (GET) bleibt frei.
const mutateLimit = rateLimit({
  max: 60, windowMs: 60_000,
  keyFn: (c) => 'u:' + (c.get('user')?.id || c.req.header('x-forwarded-for') || 'anon'),
});
app.use('/api/*', (c, next) => (c.req.method === 'GET' ? next() : mutateLimit(c, next)));
app.get('/api/me', (c) => c.json({ email: c.get('email'), role: c.get('role'), isAdmin: c.get('isAdmin'), canModerate: c.get('canModerate') }));
app.post('/api/comments', createComment);
app.delete('/api/comments/:id', deleteComment);
app.post('/api/threads', newThread);
app.route('/api/mod', mod);
app.route('/api/admin/forums', adminForums);
app.route('/api/content', content);
app.route('/api/preview', preview);
app.route('/api/publish', publish);
app.route('/api/upload', upload);
app.route('/api/profile', profile);
app.route('/api/users', users);
app.route('/api/stats', stats);

// --- Admin-SPA (im Container mitgebaut, unter /admin serviert) ---
app.get('/admin', (c) => c.redirect('/admin/'));
app.use(
  '/admin/*',
  serveStatic({
    root: ADMIN_DIR,
    rewriteRequestPath: (p) => p.replace(/^\/admin/, '') || '/',
  }),
);

// --- Vorschau (gebaut nach preview/ mit --buildDrafts) ---
app.use(
  '/_preview/*',
  serveStatic({
    root: `${SITE_DIR}/preview`,
    rewriteRequestPath: (p) => p.replace(/^\/_preview/, ''),
  }),
);

// Hochgeladene Bilder direkt aus static/ servieren — sofort sichtbar
// (Vorschau, Cover, Profilbild), ohne auf den nächsten Hugo-Build zu warten.
app.use('/images/*', serveStatic({ root: `${SITE_DIR}/static` }));

// --- Live-Site (gebaut nach public/) ---
app.use('/*', serveStatic({ root: `${SITE_DIR}/public` }));

serve({ fetch: app.fetch, port: PORT }, (info) => {
  console.log(`OPENBUREAU CMS läuft auf :${info.port} — Site + API + /_preview`);
  // Library-Beiträge als Threads in „Beiträge" spiegeln (nicht blockierend).
  syncLibrary().catch((e) => console.error('syncLibrary:', e?.message || e));
});
