/**
 * Rainmaker Twitter Bot — Grok Prompt Templates
 * Generates forecast-focused tweets for @RainmakerAIBot
 *
 * V2: Thread support, momentum posts, live edge alerts, CTA,
 *     prime-time reminders, educational content, upgraded slate/recap.
 */
import type { GrokTweetResponse, GrokThreadResponse } from './types';

const GROK_API_KEY = process.env.GROK_API_KEY || '';
const GROK_API_URL = 'https://api.x.ai/v1/chat/completions';
const GROK_MODEL = 'grok-4-1-fast-reasoning';

const SYSTEM_PROMPT = `You are the voice of Rainmaker Sports — a data-driven sports forecasting platform on Twitter/X.

Your tone: confident, sharp, insider-level. You sound like the smartest analyst in the room — not a gambler, not a hype account. You present FORECASTS with conviction backed by data.

You never use gambling language — no "bet", "wager", "lock", "fade". Instead: "forecast", "projection", "signal", "edge", "probability", "model", "value".

BRAND RULES:
- The ONLY brand name is "Rainmaker Sports" — never mention any other brand, parent company, or platform
- NEVER mention "EventheOdds", "eventheodds.ai", "SportsClaw", or any other affiliated brand
- The only website is rainmakersports.app — do not reference any other domain

FORMAT RULES:
- No character limit (X Premium supports up to 25K chars)
- No hashtags
- Do NOT include any URLs or links in the "text" field
- Do NOT include any @mentions
- Use \\n for line breaks in the JSON text field
- Keep tweets punchy and scroll-stopping — front-load the hook

ALWAYS return valid JSON only. No markdown code fences, no commentary — pure JSON.`;

// ── ET Date Formatter ───────────────────────────────────────

function formatGameDateET(dateStr: string | undefined | null): string {
  if (!dateStr) return 'TBD';
  try {
    const d = new Date(dateStr);
    if (isNaN(d.getTime())) return 'TBD';
    const weekday = d.toLocaleDateString('en-US', { timeZone: 'America/New_York', weekday: 'short' });
    const month = d.toLocaleDateString('en-US', { timeZone: 'America/New_York', month: 'short' });
    const day = d.toLocaleDateString('en-US', { timeZone: 'America/New_York', day: 'numeric' });
    const hour = d.toLocaleTimeString('en-US', { timeZone: 'America/New_York', hour: 'numeric', minute: '2-digit', hour12: true });
    return `${weekday} ${month} ${day} • ${hour.replace(/\s+/g, '')} ET`;
  } catch {
    return 'TBD';
  }
}

const LEAGUE_LABELS: Record<string, string> = {
  nba: 'NBA', nfl: 'NFL', nhl: 'NHL', mlb: 'MLB',
  ncaab: 'NCAAB', mma: 'MMA', ufc: 'UFC',
  epl: 'EPL', bundesliga: 'Bundesliga', laliga: 'La Liga',
  seriea: 'Serie A', ligue1: 'Ligue 1',
};

function getLeagueLabel(league: string): string {
  return LEAGUE_LABELS[league.toLowerCase()] || league.toUpperCase();
}

// ── Grok API Call ────────────────────────────────────────────

export async function callGrok<T = GrokTweetResponse>(
  userPrompt: string,
  retries: number = 2,
  maxTokens: number = 600
): Promise<T | null> {
  if (!GROK_API_KEY) {
    console.error('[rm-prompts] GROK_API_KEY not set');
    return null;
  }

  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const response = await fetch(GROK_API_URL, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${GROK_API_KEY}`,
        },
        body: JSON.stringify({
          model: GROK_MODEL,
          messages: [
            { role: 'system', content: SYSTEM_PROMPT },
            { role: 'user', content: userPrompt },
          ],
          temperature: 0.8,
          max_tokens: maxTokens,
        }),
        signal: AbortSignal.timeout(30000),
      });

      if (!response.ok) {
        const errText = await response.text();
        console.error(`[rm-prompts] Grok API error ${response.status} (attempt ${attempt + 1}):`, errText.slice(0, 300));
        if (attempt < retries) continue;
        return null;
      }

      const data: any = await response.json();
      let jsonStr = (data.choices?.[0]?.message?.content || '').trim();
      if (jsonStr.startsWith('```')) {
        jsonStr = jsonStr.replace(/^```(?:json)?\s*\n?/, '').replace(/\n?```\s*$/, '');
      }

      try {
        return JSON.parse(jsonStr) as T;
      } catch {
        console.warn(`[rm-prompts] JSON parse failed (attempt ${attempt + 1}), trying repair...`);
        try {
          const textMatch = jsonStr.match(/"text"\s*:\s*"((?:[^"\\]|\\.)*)"/);
          if (textMatch) {
            return { text: textMatch[1].replace(/\\"/g, '"').replace(/\\n/g, '\n') } as T;
          }
        } catch { /* repair failed */ }
        if (attempt < retries) continue;
        return null;
      }
    } catch (error) {
      console.error(`[rm-prompts] Grok call failed (attempt ${attempt + 1}):`, (error as Error).message);
      if (attempt < retries) continue;
      return null;
    }
  }
  return null;
}

// ═══════════════════════════════════════════════════════════════
// PROMPT BUILDERS
// ═══════════════════════════════════════════════════════════════

// ── Forecast Pick (standalone tweet, kept for fallback) ──────

export function forecastPickPrompt(forecast: {
  league: string;
  homeTeam: string;
  awayTeam: string;
  startsAt: string;
  summary: string;
  confidence: number;
  spread?: number | null;
  total?: number | null;
  homeML?: number | null;
  awayML?: number | null;
}): string {
  const leagueLabel = getLeagueLabel(forecast.league);
  const confPct = Math.round(forecast.confidence * 100);

  return `Generate a sports forecast tweet for Rainmaker Sports. Return JSON: { "text": "...", "pickSide": "home|away|over|under" }

"pickSide" = which side Rain Man favors.

WRITE IN THIS STRUCTURE:

📊 ${leagueLabel} FORECAST
${forecast.awayTeam} @ ${forecast.homeTeam}
${formatGameDateET(forecast.startsAt)}

[Rain Man's read — 2-3 sentences explaining the edge using the summary below]

Confidence: ${confPct}%
${forecast.spread != null ? `Spread: ${forecast.spread}` : ''}${forecast.total != null ? ` | Total: ${forecast.total}` : ''}
${forecast.homeML != null ? `Home ML: ${forecast.homeML} | Away ML: ${forecast.awayML}` : ''}

Full breakdown on rainmakersports.app

Follow Rainmaker Sports

RAIN MAN'S SUMMARY TO USE:
${forecast.summary}

IMPORTANT:
- Sound like a sports news analyst, NOT a gambler
- Use words like "forecast", "projection", "Rain Man's signals"
- Reference specific data points from the summary
- Be confident but measured`;
}

// ── Forecast Thread (anchor + 2-3 replies) ──────────────────

export function forecastThreadPrompt(forecast: {
  league: string;
  homeTeam: string;
  awayTeam: string;
  startsAt: string;
  summary: string;
  confidence: number;
  spread?: number | null;
  total?: number | null;
  homeML?: number | null;
  awayML?: number | null;
}): string {
  const leagueLabel = getLeagueLabel(forecast.league);
  const confPct = Math.round(forecast.confidence * 100);

  return `Generate a THREAD (3-4 tweets) for Rainmaker Sports. Return JSON: { "tweets": [{ "text": "...", "pickSide": "home|away" }, { "text": "..." }, { "text": "..." }, { "text": "..." }] }

Only the FIRST tweet needs "pickSide".

GAME: ${forecast.awayTeam} @ ${forecast.homeTeam}
LEAGUE: ${leagueLabel}
TIME: ${formatGameDateET(forecast.startsAt)}
CONFIDENCE: ${confPct}%
${forecast.spread != null ? `SPREAD: ${forecast.spread}` : ''}${forecast.total != null ? ` | TOTAL: ${forecast.total}` : ''}
${forecast.homeML != null ? `HOME ML: ${forecast.homeML} | AWAY ML: ${forecast.awayML}` : ''}

MODEL SUMMARY:
${forecast.summary}

THREAD STRUCTURE:

TWEET 1 (THE HOOK — must stop the scroll):
🎯 BEST EDGE: [LEAGUE]
[Team] [side] ([odds if relevant])
Confidence: ${confPct}%

Rain Man sees [one punchy line about the edge].

TWEET 2 (THE EDGE — show the math):
Model edge: [specific value difference]

Why:
• [data point 1 from summary]
• [data point 2 from summary]
• [data point 3 from summary]

TWEET 3 (THE CONTEXT — matchup narrative):
[2-3 sentences of deeper context from the summary — trends, injuries, pace, etc.]

TWEET 4 (THE CTA):
Full breakdown on rainmakersports.app

Rain Man doesn't guess. Rain Man models.
Follow Rainmaker Sports

IMPORTANT:
- Tweet 1 MUST be a scroll-stopper — lead with the strongest claim
- Tweet 2 is bullet points, not prose
- Each tweet should work standalone but flow as a thread
- Use "forecast", "signal", "model" — never gambling language
- Be confident, almost brash — this is Twitter, not a research paper`;
}

// ── PIFF Prop Pick ─────────────────────────────────────────

export function piffPropPrompt(leg: {
  name: string;
  team: string;
  stat: string;
  line: number;
  direction: string;
  tier_label: string;
  edge: number;
  prob: number;
  dvp_tier?: string;
  league?: string;
  opponent?: string;
  gameDate?: string;
}): string {
  const leagueLabel = leg.league ? getLeagueLabel(leg.league) : '';
  const edgePct = (leg.edge * 100).toFixed(0);
  const probPct = (leg.prob * 100).toFixed(0);

  return `Generate a player prop forecast tweet for Rainmaker Sports. Return JSON: { "text": "...", "pickSide": "over|under" }

You MUST set pickSide to "${leg.direction}".

WRITE IN THIS STRUCTURE:

📊 PLAYER PROP FORECAST${leagueLabel ? ` — ${leagueLabel}` : ''}
${leg.name} (${leg.team})${leg.opponent ? ` vs ${leg.opponent}` : ''}
${leg.gameDate ? formatGameDateET(leg.gameDate) : ''}

Rain Man Signal: ${leg.direction.toUpperCase()} ${leg.line} ${leg.stat}
Tier: ${leg.tier_label} | Edge: +${edgePct}% | Probability: ${probPct}%
${leg.dvp_tier ? `Defense vs Position: ${leg.dvp_tier}` : ''}

[1-2 sentences explaining why this direction, referencing the edge and tier]

Full analysis on rainmakersports.app

Follow Rainmaker Sports

IMPORTANT:
- You MUST follow the ${leg.direction} direction — do NOT contradict
- Explain the edge in plain language (e.g. "Rain Man gives this a ${probPct}% probability")
- Sound analytical, not promotional`;
}

// ── Daily Slate (UPGRADED — best bet, trap game, value dog) ──

export function dailySlatePrompt(forecasts: Array<{
  league: string;
  homeTeam: string;
  awayTeam: string;
  confidence: number;
  summary: string;
}>): string {
  const lines = forecasts.map(f => {
    const confPct = Math.round(f.confidence * 100);
    return `${getLeagueLabel(f.league)}: ${f.awayTeam} @ ${f.homeTeam} (${confPct}% conf) — ${f.summary.substring(0, 120)}`;
  });

  // The highest confidence game is the BEST
  // Lowest confidence in the top 6 could be a trap
  const bestConf = Math.round(forecasts[0]?.confidence * 100);
  const trapIdx = forecasts.length > 3 ? forecasts.length - 1 : -1;

  return `Generate a daily slate overview tweet for Rainmaker Sports. Return JSON: { "text": "..." }

WRITE IN THIS STRUCTURE (use these exact visual markers):

🧠 TODAY'S SLATE — Rain Man's Read

⭐ BEST EDGE: [highest confidence game — ${bestConf}% conf]
[One punchy line about why]

${trapIdx >= 0 ? `⚠️ TRAP WATCH: [lowest confidence game from the list]\n[Why the public might be wrong]\n` : ''}🔎 ALSO WATCHING:
• [game 2 — one line]
• [game 3 — one line]
${forecasts.length > 4 ? '• [game 4 — one line]' : ''}

Full slate on rainmakersports.app

Follow Rainmaker Sports

TODAY'S FORECASTS (use these to write the slate):
${lines.join('\n')}

IMPORTANT:
- Lead with the BEST EDGE (highest confidence) — make it feel like insider info
- The TRAP WATCH should be a game where the public is likely on the wrong side
- Keep each game to 1-2 lines max
- Sound like a morning sports desk briefing from someone who has an edge
- No gambling language — "edge", "value", "model", "signal" only`;
}

// ── Daily Recap (UPGRADED — with momentum flex) ─────────────

export function recapPrompt(results: Array<{
  league: string;
  homeTeam: string;
  awayTeam: string;
  homeScore: number;
  awayScore: number;
  ourCall?: string;
  hit?: boolean;
}>, record?: { wins: number; losses: number; winPct: number }, streak?: number): string {
  const lines = results.map(r => {
    const score = `${r.awayTeam} ${r.awayScore} - ${r.homeTeam} ${r.homeScore}`;
    const callStr = r.ourCall ? ` | Rain Man's call: ${r.ourCall} ${r.hit ? '✓' : '✗'}` : '';
    return `${getLeagueLabel(r.league)}: ${score}${callStr}`;
  });

  const hits = results.filter(r => r.hit).length;
  const total = results.filter(r => r.ourCall).length;

  let streakLine = '';
  if (streak && streak >= 3) {
    streakLine = `\nCURRENT WIN STREAK: ${streak} in a row. Mention this prominently — "Rain Man is ${streak} straight" or similar.`;
  }

  let recordLine = '';
  if (record && record.wins + record.losses >= 3) {
    recordLine = `\nOVERALL RECORD: ${record.wins}-${record.losses} (${record.winPct}%). Include this at the end.`;
  }

  return `Generate a results recap tweet for Rainmaker Sports. Return JSON: { "text": "..." }

${total > 0 && hits >= total * 0.6 ? `🔥 RESULTS — Rain Man Delivered` : `📊 FORECAST RESULTS`}

${total > 0 ? `${hits}/${total} forecasts hit today.` : 'Results from today\'s slate:'}

${lines.join('\n')}
${streakLine}${recordLine}

IMPORTANT:
- If we went 3-0, 4-1, or better — FLEX. Be confident. "Rain Man stays eating." type energy.
- If we had a losing day — own it transparently. "Not our best day. Model recalibrates."
- Tease tomorrow's slate
- End with "Follow Rainmaker Sports"
- If there's a win streak, make it the headline`;
}

// ── Momentum / Heater Post ──────────────────────────────────

export function momentumPrompt(data: {
  streak: number;
  lastN: { wins: number; losses: number; total: number };
  todayRecord?: { wins: number; losses: number };
}): string {
  return `Generate a momentum/heater tweet for Rainmaker Sports. Return JSON: { "text": "..." }

CURRENT STATUS:
- Win streak: ${data.streak} consecutive wins
- Last ${data.lastN.total} picks: ${data.lastN.wins}-${data.lastN.losses}
${data.todayRecord ? `- Today: ${data.todayRecord.wins}-${data.todayRecord.losses}` : ''}

WRITE IN THIS ENERGY:

🔥 [HEATER / STREAK / ON FIRE — pick the right vibe]

[Big stat: "Last ${data.lastN.total} picks: ${data.lastN.wins}-${data.lastN.losses}"]
[Win streak callout]

Rain Man's model is [locked in / dialed / reading the market perfectly].

Tomorrow's slate is loading.

Follow Rainmaker Sports

IMPORTANT:
- This is a FLEX tweet — confident, almost cocky but backed by real numbers
- Use the actual numbers — this is not fluff, it's a track record
- Keep it punchy — 4-6 lines max
- No gambling language
- Make people feel like they're missing out if they don't follow`;
}

// ── Live Edge Alert ─────────────────────────────────────────

export function liveEdgePrompt(forecast: {
  league: string;
  homeTeam: string;
  awayTeam: string;
  startsAt: string;
  confidence: number;
  spread?: number | null;
  total?: number | null;
  summary: string;
}): string {
  const leagueLabel = getLeagueLabel(forecast.league);
  const confPct = Math.round(forecast.confidence * 100);

  return `Generate a LIVE EDGE ALERT tweet for Rainmaker Sports. Return JSON: { "text": "...", "pickSide": "home|away|over|under" }

This is a REACTIVE alert — our model has detected significant value on an upcoming game.

GAME: ${forecast.awayTeam} @ ${forecast.homeTeam}
LEAGUE: ${leagueLabel}
TIPS OFF: ${formatGameDateET(forecast.startsAt)}
CONFIDENCE: ${confPct}%
${forecast.spread != null ? `MARKET SPREAD: ${forecast.spread}` : ''}
${forecast.total != null ? `MARKET TOTAL: ${forecast.total}` : ''}

MODEL SUMMARY: ${forecast.summary}

WRITE IN THIS STRUCTURE:

🚨 EDGE ALERT — ${leagueLabel}
${forecast.awayTeam} @ ${forecast.homeTeam}
${formatGameDateET(forecast.startsAt)}

Rain Man's model sees [significant value / a gap the market hasn't closed].

[1-2 sentences about the specific edge from the summary]

Confidence: ${confPct}%

Move fast — edges close.

Follow Rainmaker Sports

IMPORTANT:
- This should feel URGENT — like breaking news, not a scheduled post
- Use "edge alert", "model detected", "value window" language
- Reference the time until game starts to create urgency
- pickSide should be the side Rain Man favors`;
}

// ── Prime Time Reminder (6 PM pre-game) ─────────────────────

export function primeTimePrompt(forecasts: Array<{
  league: string;
  homeTeam: string;
  awayTeam: string;
  startsAt: string;
  confidence: number;
  summary: string;
}>): string {
  const lines = forecasts.map(f => {
    const confPct = Math.round(f.confidence * 100);
    return `${getLeagueLabel(f.league)}: ${f.awayTeam} @ ${f.homeTeam} — ${confPct}% confidence — Tips: ${formatGameDateET(f.startsAt)} — ${f.summary.substring(0, 80)}`;
  });

  return `Generate a prime-time pre-game reminder tweet for Rainmaker Sports. Return JSON: { "text": "..." }

Tonight's games are about to start. Remind followers where Rain Man stands.

TONIGHT'S EDGES (games starting soon):
${lines.join('\n')}

WRITE IN THIS STRUCTURE:

🏀 TONIGHT'S EDGES — Last Call

[For each game, one punchy line:]
• [Team] [side]: [one-liner from summary] (${Math.round(forecasts[0]?.confidence * 100)}%)
${forecasts.length > 1 ? `• [Team 2] [side]: [one-liner] (XX%)\n` : ''}
Games tip in [approximate time].

Full breakdowns on rainmakersports.app

Follow Rainmaker Sports

IMPORTANT:
- Create urgency — games are TONIGHT, edges are closing
- Keep each game to one line — this is a reminder, not a deep dive
- Sound like a coach giving final instructions before game time
- Make people feel they need to check rainmakersports.app RIGHT NOW`;
}

// ── CTA / Conversion Tweet ──────────────────────────────────

const CTA_ANGLES = [
  {
    angle: 'value_prop',
    hook: 'Most people follow picks. We follow edges.',
    body: 'Rain Man models every game. Every prop. Every line movement. Then tells you where the value is — not where the crowd is going.',
  },
  {
    angle: 'social_proof',
    hook: 'We don\'t talk about our record enough.',
    body: 'While everyone\'s chasing parlays, Rain Man quietly finds edges the market hasn\'t priced in. Our model runs 24/7 so you don\'t have to.',
  },
  {
    angle: 'problem_solution',
    hook: 'If you\'re tailing random picks on Twitter, you\'re guessing.',
    body: 'Rain Man doesn\'t guess. Every forecast is backed by composite modeling — pace, matchup data, defensive rankings, and market inefficiency analysis.',
  },
  {
    angle: 'transparency',
    hook: 'Here\'s how Rain Man actually works.',
    body: 'We pull live odds, run them through PIFF (our player prop model), layer in defensive matchup data, and output a confidence score. No vibes. No gut feelings. Just math.',
  },
  {
    angle: 'fomo',
    hook: 'You don\'t need more picks. You need better process.',
    body: 'Rain Man shows you WHERE the value is and WHY the market is mispriced. Every edge, every game, every day.',
  },
  {
    angle: 'free_access',
    hook: 'We publish our edges for free. Yes, really.',
    body: 'Full slate. Confidence scores. Model summaries. Player prop signals. All on rainmakersports.app — no paywall on the forecast feed.',
  },
];

export function ctaPrompt(dayOfYear: number, record?: { wins: number; losses: number; winPct: number }): string {
  const angle = CTA_ANGLES[dayOfYear % CTA_ANGLES.length];

  let recordContext = '';
  if (record && record.wins + record.losses >= 5) {
    recordContext = `\nOur current record: ${record.wins}-${record.losses} (${record.winPct}%). Weave this in naturally if it supports the message.`;
  }

  return `Generate a conversion/CTA tweet for Rainmaker Sports. Return JSON: { "text": "..." }

ANGLE: ${angle.angle}
HOOK: ${angle.hook}
BODY DIRECTION: ${angle.body}
${recordContext}

Write a tweet that:
1. Opens with a hook that stops the scroll (use the HOOK above as inspiration, don't copy verbatim)
2. Delivers 2-3 lines of value/insight
3. Ends with a soft CTA to rainmakersports.app

IMPORTANT:
- This is NOT a pick tweet — it's a BRAND tweet
- Sound like the smartest person in the room, not a salesperson
- No gambling language — "forecast", "model", "edge", "value"
- Maximum 6-8 lines total — punchy, not preachy
- End with "Follow Rainmaker Sports"
- Do NOT hard sell — intrigue them`;
}

// ── Educational Content ─────────────────────────────────────

const EDUCATIONAL_TOPICS = [
  {
    topic: 'sharp_vs_public',
    title: 'Sharp vs Public Money',
    content: 'Explain the difference between sharp money (professional bettors who move lines) and public money (casual bettors who follow favorites). Rain Man\'s model captures this by tracking line movement patterns and identifying when the market overreacts to public sentiment.',
  },
  {
    topic: 'what_is_edge',
    title: 'What Is Edge?',
    content: 'Edge = the gap between what the market says and what the data says. If the market says a team wins 55% of the time but our model says 62%, that\'s a +7% edge. Rain Man finds these gaps across every game, every day.',
  },
  {
    topic: 'why_most_lose',
    title: 'Why Most People Lose',
    content: 'Most people lose because they chase results instead of process. They tail hot streaks, double down after losses, and ignore probability. Rain Man doesn\'t have emotions. It has a model. That\'s the difference.',
  },
  {
    topic: 'clv_explained',
    title: 'Closing Line Value',
    content: 'CLV = Closing Line Value. It measures whether you got a better number than the final line. If you grab a team at -3 and it closes at -5, you captured 2 points of CLV. This is the single best predictor of long-term profitability. Rain Man tracks it on every signal.',
  },
  {
    topic: 'line_movement',
    title: 'Reading Line Movement',
    content: 'When a line moves from -3 to -5 in 30 minutes, that\'s not random — it\'s information. Sharp money hit it. Rain Man monitors these movements in real-time and flags when our model agrees with the sharp side.',
  },
  {
    topic: 'model_transparency',
    title: 'How Rain Man\'s Model Works',
    content: 'Rain Man combines pace data, defensive matchup rankings (DVP), recent form, H2H history, and market odds into a composite confidence score. No single factor dominates — it\'s the weighted combination that finds edges humans miss.',
  },
  {
    topic: 'prop_modeling',
    title: 'How We Model Player Props',
    content: 'PIFF (our prop model) looks at: season hit rate, last 5/10 game trends, defense vs position (DVP), head-to-head history, and the gap between the line and projected output. Only T1 (Lock) and T2 (Strong) tier signals get published.',
  },
];

export function educationalPrompt(dayOfYear: number): string {
  const topic = EDUCATIONAL_TOPICS[dayOfYear % EDUCATIONAL_TOPICS.length];

  return `Generate an educational/authority tweet for Rainmaker Sports. Return JSON: { "text": "..." }

TOPIC: ${topic.title}

CONTENT TO TEACH:
${topic.content}

Write a tweet that:
1. Opens with a bold statement or question that hooks sports fans
2. Teaches the concept in 3-4 plain-language sentences
3. Ties it back to how Rain Man / Rainmaker Sports uses this
4. Ends with "Follow Rainmaker Sports"

STRUCTURE:
🧠 [Bold opening line — a statement, not a question]

[2-3 sentences explaining the concept simply]

[1 sentence tying it to Rain Man's model]

This is how we find edges others miss.

Follow Rainmaker Sports

IMPORTANT:
- Sound like a teacher who also happens to be really good at this, not a textbook
- Use concrete examples (specific numbers, scenarios)
- Keep it under 8 lines
- No gambling language
- The goal is to make followers think "these people actually know what they're doing"`;
}

// ── Free Question Answer (existing) ──────────────────────────

export function freeQuestionAnswerPrompt(question: string, forecastData: string): string {
  return `Generate an answer to this user's sports question for Rainmaker Sports. Return JSON: { "text": "..." }

THEIR QUESTION: "${question}"

DATA FROM OUR FORECASTS:
${forecastData}

Answer with enough data to be helpful but keep them wanting more. Reference our forecast models.
End with: "Full analysis at rainmakersports.app — Follow Rainmaker Sports"
Keep under 280 chars total. No hashtags. No @mentions. No URLs other than rainmakersports.app.`;
}
