'use strict';

/**
 * Content formatter (Session 29).
 *
 * Transforms structured content objects (from contentTemplateService) into
 * platform-ready PLAIN TEXT — suitable for X threads / Telegram. Image
 * formatting is a separate design-layer concern. Pure + defensive: a
 * missing field renders as a sensible blank, never "undefined".
 */

function fmtOdds(o) {
  const n = Number(o);
  if (!Number.isFinite(n)) return String(o ?? '');
  return n > 0 ? `+${n}` : `${n}`;
}

function fmtTime(iso) {
  if (!iso) return '';
  try {
    return new Date(iso).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', timeZoneName: 'short' });
  } catch {
    return String(iso);
  }
}

function formatPickPost(p) {
  const lines = [`${p.player} · ${p.stat} ${p.side || ''} ${p.line ?? ''}`.replace(/\s+/g, ' ').trim()];
  lines.push(`Grade: ${p.grade}${p.confidence ? ` · ${p.confidence}% confidence` : ''}`);
  if (p.edge) lines.push(`Edge: ${p.edge > 0 ? '+' : ''}${p.edge}%`);
  if (p.analysis) lines.push(p.analysis);
  return lines.join('\n');
}

function formatGameHighlight(p) {
  const parts = [`${p.game}${p.time ? ` · ${fmtTime(p.time)}` : ''}`];
  if (p.bestAwayML) parts.push(`Best away ML: ${fmtOdds(p.bestAwayML.odds)} (${p.bestAwayML.book})`);
  if (p.bestHomeML) parts.push(`Best home ML: ${fmtOdds(p.bestHomeML.odds)} (${p.bestHomeML.book})`);
  if (p.total != null) parts.push(`O/U ${p.total}`);
  if (p.bookCount) parts.push(`${p.bookCount} books`);
  return parts.join('\n');
}

function formatMovers(p) {
  const head = '📈 Biggest line moves:';
  const rows = (p.movers || []).map((m) => {
    const d = m.delta > 0 ? `+${m.delta}` : `${m.delta}`;
    return `${m.player} ${String(m.stat || '').replace(/_/g, ' ')}: ${m.opening ?? '?'} → ${m.current ?? '?'} (${d})${m.sharpSignal ? ' ⚡' : ''}`;
  });
  return [head, ...rows].join('\n');
}

function formatSchedule(p) {
  return (p.games || [])
    .map((g) => `${g.away || '?'} @ ${g.home || '?'}${g.time ? ` · ${fmtTime(g.time)}` : ''}`)
    .join('\n');
}

function formatPost(post) {
  switch (post.role) {
    case 'hook': return post.text || '';
    case 'cta': return post.text || '';
    case 'pick': return formatPickPost(post);
    case 'game_highlight': return formatGameHighlight(post);
    case 'movers': return formatMovers(post);
    case 'schedule': return formatSchedule(post);
    default: return '';
  }
}

/** Returns an array of post-ready strings (one per thread post). */
function formatSlateThread(thread) {
  if (!thread || !Array.isArray(thread.posts)) return [];
  return thread.posts.map(formatPost);
}

/** Single-block POTD text. */
function formatPOTD(potd) {
  if (!potd || potd.available === false) return 'No standout pick today — check the full slate at vyndr.app.';
  if (potd.dataLevel === 'lines') {
    return `🎯 GAME OF THE DAY\n${potd.game}${potd.time ? ` · ${fmtTime(potd.time)}` : ''}\n${potd.total != null ? `O/U ${potd.total}` : ''}${potd.bestHomeML ? `\nBest home ML ${fmtOdds(potd.bestHomeML.odds)} (${potd.bestHomeML.book})` : ''}`.trim();
  }
  return `🎯 PROP OF THE DAY\n${formatPickPost(potd)}`;
}

/** Recap text block. */
function formatRecap(recap) {
  if (!recap || recap.available === false) return 'No graded results in yet today.';
  const { record, winRate } = recap;
  const lines = [`📊 VYNDR RECAP — ${recap.date}`];
  lines.push(`Record: ${record.wins}-${record.losses}${record.pushes ? `-${record.pushes}` : ''}${winRate != null ? ` (${Math.round(winRate * 100)}%)` : ''}`);
  if (recap.topHits && recap.topHits.length) {
    lines.push('Top hits:');
    for (const h of recap.topHits) lines.push(`✅ ${h.player} ${h.stat} ${h.side || ''} ${h.line ?? ''}`.replace(/\s+/g, ' ').trim());
  }
  if (recap.metrics && recap.metrics.brierScore != null) lines.push(`Brier: ${recap.metrics.brierScore}`);
  return lines.join('\n');
}

module.exports = {
  formatSlateThread,
  formatPOTD,
  formatRecap,
  __internals: { formatPost, formatPickPost, formatGameHighlight, formatMovers, formatSchedule },
};
