/**
 * routes/public.js
 * Unauthenticated public endpoints for the marketing site.
 * Used by the home page live counter and any future embed / status widgets.
 * Hard privacy rules:
 *   - No per-user data, ever.
 *   - Counts only — never returns IDs, names, emails, URLs, or timestamps that
 *     could be re-correlated to a user.
 *   - Caches for 30 seconds to absorb traffic spikes (no DB pressure from
 *     a curious crawler).
 *
 * Mock-data mode:
 *   Set PUBLIC_STATS_MOCK=1 (or true) in the environment to return
 *   curated showcase numbers instead of querying the DB. Use this while
 *   real case volume is low (early launch, pre-pilot, demo) so the home
 *   page doesn't show "7 removals" until you have real volume. The
 *   response includes `mock: true` so the client can soften the
 *   "actual case log every 60 seconds" copy when mock is active.
 *   When mock is off (default), returns the real DB-computed values
 *   as before. No code change needed to flip — just toggle the env.
 */

'use strict';

const express = require('express');
const router  = express.Router();
const db      = require('../config/db');
const { logger } = require('../middleware/logger');

// 30-second in-process cache
let _cache = { at: 0, payload: null };
const CACHE_TTL_MS = 30_000;

// Showcase numbers — used only when PUBLIC_STATS_MOCK=1. Picked to look
// like an early-growth SaaS doing real work, not an inflated ad claim.
// Easy to tune: edit these four constants.
const MOCK_STATS = {
  cases:      38,    // active cases
  removals:   247,   // removals filed
  avg_hours:  1.4,   // avg hours to first takedown
  uptime_pct: 96,    // removal success rate last 30d
};

function isMockMode() {
  const v = (process.env.PUBLIC_STATS_MOCK || '').toString().trim().toLowerCase();
  return v === '1' || v === 'true' || v === 'yes' || v === 'on';
}

function computeStats() {
  if (isMockMode()) {
    return {
      cases:      MOCK_STATS.cases,
      removals:   MOCK_STATS.removals,
      avg_hours:  MOCK_STATS.avg_hours,
      uptime_pct: MOCK_STATS.uptime_pct,
      mock:       true,
      // updated_at is a client-side cache buster — server time of the
      // last refresh, not a promise about underlying data freshness.
      updated_at: Math.floor(Date.now() / 1000),
    };
  }

  // Active cases = cases that are not archived / closed.
  // Active cases = cases that are not archived / closed.
  const cases = db.db.prepare(
    "SELECT COUNT(*) c FROM cases WHERE status NOT IN ('archived','closed','deleted')"
  ).get().c;

  // Removals filed = takedowns that left draft (excludes drafts/test data).
  const removals = db.db.prepare(
    "SELECT COUNT(*) c FROM takedowns WHERE status NOT IN ('draft','queued') AND is_test_data = 0"
  ).get().c;

  // Avg hours to first takedown. sent_at and created_at are stored as
  // INTEGER milliseconds, so we do integer math instead of julianday
  // (julianday on an integer returns null).
  const avgRow = db.db.prepare(
    "SELECT AVG( (sent_at - created_at) / 1000.0 / 3600.0 ) AS h " +
    "FROM takedowns WHERE sent_at IS NOT NULL AND is_test_data = 0"
  ).get();

  // Removal success rate over the last 30 days. Counts all statuses
  // that mean the content is no longer reachable as a success:
  //   'removed'   — host returned 404 / 410
  //   'blocked'   — host actively returns 403 (also a success)
  //   'soft_404'  — page returns 200 but the content is gone
  // Returns null if there's no data in the 30-day window. The home
  // page labels this "platform uptime" for short.
  const thirtyDaysAgoMs = Date.now() - 30 * 86400 * 1000;
  const upRow = db.db.prepare(
    "SELECT " +
    "  CAST(SUM(CASE WHEN status IN ('removed','blocked','soft_404') THEN 1 ELSE 0 END) AS REAL) * 1.0 / NULLIF(COUNT(*), 0) AS ratio " +
    "FROM link_health_checks " +
    "WHERE checked_at >= ?"
  ).get(thirtyDaysAgoMs);

  return {
    cases:        cases,
    removals:     removals,
    avg_hours:    avgRow && avgRow.h != null ? Number(avgRow.h.toFixed(1)) : null,
    uptime_pct:   upRow && upRow.ratio != null ? Math.round(upRow.ratio * 100) : null,
    // updated_at is a client-side cache buster — not a server timestamp we
    // promise, just tells the UI "this was the data at the time of fetch".
    updated_at:   Math.floor(Date.now() / 1000),
  };
}

router.get('/api/public/stats', (_req, res) => {
  try {
    const now = Date.now();
    if (!_cache.payload || now - _cache.at > CACHE_TTL_MS) {
      _cache.payload = computeStats();
      _cache.at = now;
    }
    // short browser cache so a refresh doesn't slam the DB
    res.set('Cache-Control', 'public, max-age=30');
    res.json(_cache.payload);
  } catch (err) {
    logger.error('public.stats.error', { message: err.message });
    // Fail soft — UI shows "—" placeholders, no NaN.
    res.status(200).json({
      cases: null, removals: null, avg_hours: null, uptime_pct: null,
      updated_at: Math.floor(Date.now() / 1000),
    });
  }
});

module.exports = router;
