/**
 * News Scout Pipeline — Phase 4: Grok AI Headline Generation
 *
 * Batches 5 headlines per LLM call for the top 10-12 stories.
 * Generates custom_headline, custom_summary, celebrity_names.
 * Tracks usage to rm_api_usage.
 */

import pool from '../../db';
import { ScoutCandidate } from './types';

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

const BATCH_SIZE = 5;
const MAX_CURATED = 12;

const SYSTEM_PROMPT = `You are the editorial voice of Rainmaker Sports — skeptical, analytical, market-aware. You rewrite headlines through the lens of a sharp sports analyst who always asks: "What does this mean for the number?"
Rules:
- No gambling language (no "bet", "wager", "odds", "lock", "parlay" in headlines)
- Headlines should be 8-12 words, active voice, with a contrarian or analytical edge
- When a star is injured, mention the market impact (e.g., "line shift", "spread implications")
- When a team is streaking, question whether the market already prices it in
- When a trade or signing happens, frame it as what changes for the team's projection
- Summaries should be 2-3 sentences — lead with the analytical angle, then the facts
- Extract any notable athlete or celebrity names mentioned
- Use ALL CAPS for team abbreviations (NFL, NBA, etc.)
- Be accurate — do not fabricate facts or market numbers you don't have
- Tone: confident skeptic, not hype man. Question narratives, highlight what others miss.`;

interface GrokHeadlineResult {
  index: number;
  custom_headline: string;
  custom_summary: string;
  celebrity_names: string[];
}

async function callGrokBatch(items: { index: number; title: string; description: string; source: string; sport: string }[]): Promise<GrokHeadlineResult[]> {
  const startTime = Date.now();

  const userPrompt = `Rewrite these ${items.length} sports stories with Rainmaker's skeptical analyst voice. For every story, ask yourself: "What does this change about the numbers?" Frame injuries as line movers, streaks as potential overreactions, trades as projection shifts.

For each item, return a JSON array with objects containing:
- "index": the item's index number
- "custom_headline": a sharp 8-12 word headline with an analytical or contrarian edge
- "custom_summary": a 2-3 sentence summary that leads with the market/analytical angle
- "celebrity_names": array of notable people mentioned (athletes, celebrities)

Stories:
${items.map(item => `[${item.index}] "${item.title}" (${item.source}, ${item.sport})${item.description ? `\n    ${item.description.slice(0, 200)}` : ''}`).join('\n\n')}

Return ONLY valid JSON array, no markdown fences.`;

  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.7,
        max_tokens: 1500,
      }),
      signal: AbortSignal.timeout(30000),
    });

    if (!response.ok) {
      const errText = await response.text();
      throw new Error(`Grok API ${response.status}: ${errText}`);
    }

    const data: any = await response.json();
    const content = data.choices?.[0]?.message?.content || '';
    const inputTokens = data.usage?.prompt_tokens || 0;
    const outputTokens = data.usage?.completion_tokens || 0;
    const totalTokens = data.usage?.total_tokens || 0;

    // Track usage
    pool.query(
      `INSERT INTO rm_api_usage (category, subcategory, provider, model, input_tokens, output_tokens, total_tokens, response_time_ms, success)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true)`,
      ['news_curation', 'headline_generation', 'grok', GROK_MODEL, inputTokens, outputTokens, totalTokens, Date.now() - startTime]
    ).catch(() => {});

    // Parse JSON — strip markdown fences if present
    let cleaned = content.replace(/```json\s*/g, '').replace(/```\s*/g, '').trim();

    // Try to extract JSON array
    const arrMatch = cleaned.match(/\[[\s\S]*\]/);
    if (arrMatch) cleaned = arrMatch[0];

    const results: GrokHeadlineResult[] = JSON.parse(cleaned);
    return results.filter(r => r.custom_headline && r.custom_summary);
  } catch (err: any) {
    console.error(`  [curator] Grok batch call failed: ${err.message}`);

    // Track failed usage
    pool.query(
      `INSERT INTO rm_api_usage (category, subcategory, provider, model, response_time_ms, success, error_message)
       VALUES ($1, $2, $3, $4, $5, false, $6)`,
      ['news_curation', 'headline_generation', 'grok', GROK_MODEL, Date.now() - startTime, err.message]
    ).catch(() => {});

    return [];
  }
}

export async function runCurator(candidates: ScoutCandidate[]): Promise<ScoutCandidate[]> {
  if (!GROK_API_KEY) {
    console.log('[curator] No GROK_API_KEY — skipping curation');
    return candidates;
  }

  // Only curate the top N by engagement score
  const toCurate = candidates.slice(0, MAX_CURATED);
  console.log(`[curator] Curating top ${toCurate.length} stories via Grok`);

  // Process in batches of 5
  for (let i = 0; i < toCurate.length; i += BATCH_SIZE) {
    const batch = toCurate.slice(i, i + BATCH_SIZE);
    const batchItems = batch.map((c, idx) => ({
      index: i + idx,
      title: c.title,
      description: c.description,
      source: c.source,
      sport: c.sport,
    }));

    const results = await callGrokBatch(batchItems);

    for (const result of results) {
      const candidate = toCurate[result.index];
      if (!candidate) continue;

      candidate.customHeadline = result.custom_headline;
      candidate.customSummary = result.custom_summary;
      candidate.isCurated = true;

      if (result.celebrity_names && result.celebrity_names.length > 0) {
        // Merge with any existing celebrity names
        const existing = new Set(candidate.celebrityNames || []);
        for (const name of result.celebrity_names) existing.add(name);
        candidate.celebrityNames = [...existing];
      }
    }

    console.log(`  [curator] Batch ${Math.floor(i / BATCH_SIZE) + 1}: ${results.length}/${batch.length} curated`);
  }

  const curatedCount = toCurate.filter(c => c.isCurated).length;
  console.log(`[curator] Total curated: ${curatedCount}/${toCurate.length}`);
  return candidates;
}
