'use strict';

/**
 * /api/content (Session 29)
 *
 * Structured content objects generated from live VYNDR data, degrading
 * gracefully by data level. Read-only, zero-credit (reads cached data).
 * `?format=text` additionally returns post-ready plain text.
 *
 *   GET /api/content/slate/:sport            → daily slate thread
 *   GET /api/content/potd/:sport             → prop (or game) of the day
 *   GET /api/content/recap/:sport            → results recap (needs resolved grades)
 *   GET /api/content/preview/:sport/:gameId  → matchup preview for one game
 */

const express = require('express');
const template = require('../services/contentTemplateService');
const formatter = require('../services/contentFormatter');
const { cacheGet } = require('../utils/redis');
const { createRateLimit } = require('../middleware/rateLimit');

const router = express.Router();
// Session 32 — public throttle (60/min; reads from cache).
router.use(createRateLimit({ windowMs: 60_000, max: 60 }));

const MISSION_HEADER = { 'X-VYNDR-Mission': 'Every post is a free ad' };
const SUPPORTED = new Set(['nba', 'wnba', 'mlb', 'soccer', 'nfl', 'nhl']);

function guard(req, res) {
  const sport = String(req.params.sport || '').toLowerCase();
  if (!SUPPORTED.has(sport)) {
    res.status(404).set(MISSION_HEADER).json({ error: `No content for sport: ${sport}` });
    return null;
  }
  return sport;
}

/**
 * Session 60 (night2/G, spec §12) — the aggregator's content formats.
 *
 * GET /top-signals/:sport — tonight's top graded props (snapshot cache).
 * GET /streak-watch/:sport — the DAILY ZERO-GRADE FORMAT: real streaks
 *   through the lens; postable even on a morning with no lines.
 * GET /daily-report/:sport — the settled-record report. BUILT but flagged
 *   DO-NOT-POST until the record clears n≥20: the payload carries
 *   `do_not_post: true` until then. Flag, don't fake.
 */
router.get('/top-signals/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    const snap = await cacheGet(`snapshot:${sport}:latest`);
    const grades = (snap && Array.isArray(snap.grades) ? snap.grades : [])
      .filter((g) => g.grade && !g.outcome)
      .sort((a, b) => (Number(b.confidence) || 0) - (Number(a.confidence) || 0))
      .slice(0, 5)
      .map((g) => ({
        player: g.player || g.player_name, team: g.team || null,
        stat: g.stat_type || g.stat, line: g.line,
        side: String(g.direction || 'over').toLowerCase(), grade: g.grade,
        archetype: g.archetype || null,
        locked_at: (g.gradedAt && g.gradedAt.timestamp) || null,
      }));
    res.set('Cache-Control', 'public, max-age=300');
    return res.set(MISSION_HEADER).json({
      sport, format: 'top-signals', updated_at: snap && snap.updated_at,
      dataLevel: grades.length > 0 ? 'full' : 'empty', signals: grades,
    });
  } catch (err) {
    console.error(`[content/top-signals/${sport}]`, err.message);
    return res.set(MISSION_HEADER).json({ sport, format: 'top-signals', dataLevel: 'empty', signals: [] });
  }
});

router.get('/streak-watch/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    const { loadRosterLogs } = require('../services/rosterLogs');
    const streaksService = require('../services/streaksService');
    const { applyLens } = require('../services/streakLens');
    const roster = await loadRosterLogs(sport);
    const rows = [
      ...streaksService.computeStreaks(roster, sport, { limit: 8 }),
      ...streaksService.computeFormHeat(roster, sport, { limit: 4 }),
    ];
    const todayET = new Intl.DateTimeFormat('en-CA', { timeZone: 'America/New_York' }).format(new Date());
    const sched = await cacheGet(`schedule:${sport}:${todayET}`);
    const withLens = applyLens(rows, { scheduleGames: Array.isArray(sched) ? sched : [], pitcherGames: [] });
    res.set('Cache-Control', 'public, max-age=600');
    return res.set(MISSION_HEADER).json({
      sport, format: 'streak-watch',
      dataLevel: withLens.length > 0 ? 'full' : 'empty',
      streaks: withLens.map((r) => ({ player: r.player, team: r.team, description: r.description, read: r.lens && r.lens.read, streak: r.currentStreak })),
    });
  } catch (err) {
    console.error(`[content/streak-watch/${sport}]`, err.message);
    return res.set(MISSION_HEADER).json({ sport, format: 'streak-watch', dataLevel: 'empty', streaks: [] });
  }
});

router.get('/daily-report/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    const ledgerService = require('../services/ledgerService');
    const agg = await ledgerService.getModelAggregate({ sport });
    const ready = agg.settled >= (agg.min_sample || 20) && agg.hit_pct != null;
    res.set('Cache-Control', 'public, max-age=600');
    return res.set(MISSION_HEADER).json({
      sport, format: 'daily-report',
      do_not_post: !ready,
      reason: ready ? null : `record building — ${agg.settled}/${agg.min_sample || 20} settles`,
      aggregate: agg,
    });
  } catch (err) {
    console.error(`[content/daily-report/${sport}]`, err.message);
    return res.set(MISSION_HEADER).json({ sport, format: 'daily-report', do_not_post: true, reason: 'unavailable' });
  }
});

router.get('/slate/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    const data = await template.collectSlateData(sport);
    const thread = template.generateSlateThread(sport, data);
    const body = { ...thread };
    if (req.query.format === 'text') body.text = formatter.formatSlateThread(thread);
    return res.set(MISSION_HEADER).json(body);
  } catch (err) {
    console.error(`[content/slate/${sport}]`, err.message);
    return res.status(500).set(MISSION_HEADER).json({ error: 'Content generation failed' });
  }
});

router.get('/potd/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    const data = await template.collectSlateData(sport);
    const potd = template.generatePOTD(sport, data);
    const body = { ...potd };
    if (req.query.format === 'text') body.text = formatter.formatPOTD(potd);
    return res.set(MISSION_HEADER).json(body);
  } catch (err) {
    console.error(`[content/potd/${sport}]`, err.message);
    return res.status(500).set(MISSION_HEADER).json({ error: 'Content generation failed' });
  }
});

router.get('/recap/:sport', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  try {
    // Resolved grades land in a daily cache when the grading flow settles.
    const utc = new Date().toISOString().split('T')[0];
    const cache = (await cacheGet(`results:${sport}:${utc}`)) ?? (await cacheGet(`results:${sport}`));
    const resolved = Array.isArray(cache) ? cache : Array.isArray(cache?.grades) ? cache.grades : [];
    const recap = template.generateResultsRecap(sport, resolved);
    const body = { ...recap };
    if (req.query.format === 'text') body.text = formatter.formatRecap(recap);
    return res.set(MISSION_HEADER).json(body);
  } catch (err) {
    console.error(`[content/recap/${sport}]`, err.message);
    return res.status(500).set(MISSION_HEADER).json({ error: 'Content generation failed' });
  }
});

router.get('/preview/:sport/:gameId', async (req, res) => {
  const sport = guard(req, res);
  if (!sport) return undefined;
  const { gameId } = req.params;
  try {
    const data = await template.collectSlateData(sport);
    const game = (data.schedule || []).find((g) => String(g.id) === String(gameId));
    if (!game) {
      return res.status(404).set(MISSION_HEADER).json({ error: 'Game not on today\'s schedule.' });
    }
    const lines = template.__internals.findGameLinesFor(game, data.gameLines);
    const preview = template.generateMatchupPreview(game, lines, data.streaks);
    return res.set(MISSION_HEADER).json(preview);
  } catch (err) {
    console.error(`[content/preview/${sport}]`, err.message);
    return res.status(500).set(MISSION_HEADER).json({ error: 'Content generation failed' });
  }
});

module.exports = router;
