import { Router, Request, Response } from 'express';
import rateLimit from 'express-rate-limit';
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';

const router = Router();

const SGO_API_KEY = process.env.SGO_API_KEY || '';
const GROK_API_KEY = process.env.GROK_API_KEY || '';
const SGO_BASE = 'https://api.sportsgameodds.com/v2';
const GROK_BASE = 'https://api.x.ai/v1';
const COOKIE_STORE_PATH = path.join(__dirname, '..', 'demo-cookie-store.json');
const COOKIE_NAME = 'sc_demo';

// Rate limit: 3 requests per minute per IP (burst protection)
const demoLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 3,
  message: { error: 'Too many requests. Try again in a minute.' },
  standardHeaders: true,
  legacyHeaders: false,
});

router.use(demoLimiter);

// --- Cookie-based tracking (1 free query per day) ---

interface CookieStore {
  [token: string]: number; // timestamp of last query
}

function loadCookieStore(): CookieStore {
  try {
    if (fs.existsSync(COOKIE_STORE_PATH)) {
      return JSON.parse(fs.readFileSync(COOKIE_STORE_PATH, 'utf-8'));
    }
  } catch {}
  return {};
}

function saveCookieStore(store: CookieStore): void {
  try {
    fs.writeFileSync(COOKIE_STORE_PATH, JSON.stringify(store));
  } catch (e) {
    console.error('Failed to save cookie store:', e);
  }
}

function ensureCookie(req: Request, res: Response): string {
  let token = req.cookies?.[COOKIE_NAME];
  if (!token) {
    token = crypto.randomUUID();
    res.cookie(COOKIE_NAME, token, {
      httpOnly: true,
      secure: true,
      sameSite: 'lax',
      maxAge: 365 * 24 * 60 * 60 * 1000, // 1 year
      path: '/',
    });
  }
  return token;
}

function hasUsedFreeQuery(token: string): boolean {
  const store = loadCookieStore();
  const lastQuery = store[token];
  if (!lastQuery) return false;
  const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
  return lastQuery > oneDayAgo;
}

function markTokenUsed(token: string): void {
  const store = loadCookieStore();
  // Clean entries older than 24h
  const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
  for (const key of Object.keys(store)) {
    if (store[key] < oneDayAgo) {
      delete store[key];
    }
  }
  store[token] = Date.now();
  saveCookieStore(store);
}

// --- Grok + SGO query engine ---

async function callGrok(prompt: string, systemPrompt: string): Promise<string> {
  const resp = await fetch(`${GROK_BASE}/chat/completions`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${GROK_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'grok-3-mini-fast',
      messages: [
        { role: 'system', content: systemPrompt },
        { role: 'user', content: prompt },
      ],
      temperature: 0.3,
      max_tokens: 800,
    }),
  });
  const data = await resp.json() as any;
  return data.choices?.[0]?.message?.content || '';
}

async function fetchSGO(endpoint: string, params: Record<string, any> = {}): Promise<any> {
  const url = new URL(`${SGO_BASE}/${endpoint}`);
  for (const [k, v] of Object.entries(params)) {
    if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
  }
  const resp = await fetch(url.toString(), {
    headers: { 'x-api-key': SGO_API_KEY },
  });
  return resp.json();
}

function formatOdds(val: any): string {
  if (!val || val === '-') return '-';
  return String(val);
}

async function handleSportsQuery(query: string): Promise<{ title: string; lines: string[]; emoji: string }> {
  // Step 1: Use Grok to figure out what SGO API call to make
  const planPrompt = `You are a sports data query planner. Given a user question about sports odds/props, determine the best SportsGameOdds API call to make.

Available API endpoints:
- events: Fetch games with odds. Params: leagueID (NBA, NFL, MLB, NHL, UFC, NCAAB, EPL), oddsAvailable (true), limit (number)
- players: Search players. Params: leagueID, teamID, limit
- teams: Get teams. Params: leagueID

League IDs: NBA, NFL, MLB, NHL, UFC, NCAAB, NCAAF, EPL, LALIGA, SERIEA, MLS, WNBA

Respond in JSON only:
{"endpoint": "events", "params": {"leagueID": "NBA", "oddsAvailable": true, "limit": 5}, "queryType": "odds|props|matchup|spreads", "focus": "optional team or player name to highlight"}

User query: "${query}"`;

  let plan: any;
  try {
    const planJson = await callGrok(planPrompt, 'You are a concise JSON-only API planner. Respond with valid JSON only, no markdown.');
    // Extract JSON from response
    const jsonMatch = planJson.match(/\{[\s\S]*\}/);
    plan = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
  } catch (e) {
    console.error('Grok plan error:', e);
    plan = null;
  }

  if (!plan) {
    // Fallback: default to NBA odds
    plan = { endpoint: 'events', params: { leagueID: 'NBA', oddsAvailable: true, limit: 5 }, queryType: 'odds', focus: '' };
  }

  // Step 2: Call SGO API
  const sgoData = await fetchSGO(plan.endpoint, plan.params);
  const events = sgoData.data || [];

  if (events.length === 0) {
    return {
      emoji: '🎯',
      title: 'No Data Available',
      lines: [`No ${plan.params?.leagueID || 'sports'} data found right now.`, 'Try a different sport or check back later.'],
    };
  }

  // Step 3: Use Grok to format the response nicely
  // Build a condensed data summary for Grok
  const condensed = events.slice(0, 5).map((e: any) => {
    const home = e.teams?.home?.names || {};
    const away = e.teams?.away?.names || {};
    const odds = e.odds || {};
    const status = e.status || {};

    const mlHome = odds['points-home-game-ml-home']?.fairOdds;
    const mlAway = odds['points-away-game-ml-away']?.fairOdds;
    const spHome = odds['points-home-game-sp-home']?.fairSpread;
    const ouOver = odds['points-all-game-ou-over'];
    const ou = ouOver?.fairOverUnder || ouOver?.bookOverUnder;

    // Find player props if any
    const playerProps: any[] = [];
    for (const [k, v] of Object.entries(odds)) {
      if (k.startsWith('points-') && k.includes('-game-ou-over') && k !== 'points-all-game-ou-over') {
        const pid = k.split('-')[1];
        const pName = pid.replace(/_NBA|_NFL|_MLB|_NHL/g, '').replace(/_\d+$/, '').replace(/_/g, ' ');
        const pv = v as any;
        playerProps.push({
          name: pName,
          line: pv.fairOverUnder || pv.bookOverUnder,
          over: pv.fairOdds,
          under: odds[k.replace('-over', '-under')]?.fairOdds,
        });
      }
    }

    return {
      home: home.medium || home.short,
      away: away.medium || away.short,
      homeShort: home.short,
      awayShort: away.short,
      time: status.startsAt,
      live: status.live,
      completed: status.completed,
      mlHome, mlAway, spread: spHome, ou,
      playerProps: playerProps.slice(0, 3),
    };
  });

  const focus = plan.focus ? `Focus on: ${plan.focus}` : '';

  const formatPrompt = `Format this sports data into 3-5 short display lines for a card UI. Be concise — each line should be under 50 chars. No markdown, no bullets, just plain text lines.

Query: "${query}"
${focus}
Query type: ${plan.queryType}

Data:
${JSON.stringify(condensed, null, 2)}

Respond as JSON: {"title": "Short card title", "lines": ["line 1", "line 2", ...], "emoji": "single emoji"}`;

  try {
    const formatted = await callGrok(formatPrompt, 'You format sports data into concise card displays. Respond with valid JSON only.');
    const jsonMatch = formatted.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
      const result = JSON.parse(jsonMatch[0]);
      return {
        emoji: result.emoji || '🎯',
        title: result.title || 'Results',
        lines: Array.isArray(result.lines) ? result.lines.slice(0, 6) : ['No data formatted'],
      };
    }
  } catch (e) {
    console.error('Grok format error:', e);
  }

  // Fallback: manual format
  const first = condensed[0];
  if (first) {
    return {
      emoji: '🏀',
      title: `${first.awayShort} @ ${first.homeShort}`,
      lines: [
        `ML: ${formatOdds(first.mlAway)} / ${formatOdds(first.mlHome)}`,
        `Spread: ${first.homeShort} ${formatOdds(first.spread)}`,
        `O/U: ${formatOdds(first.ou)}`,
      ],
    };
  }

  return { emoji: '🎯', title: 'Results', lines: ['Data retrieved but could not be formatted.'] };
}

// --- Routes ---

router.post('/query', async (req: Request, res: Response) => {
  try {
    const { query } = req.body;

    if (!query || typeof query !== 'string' || query.trim().length < 2) {
      return res.status(400).json({ error: 'Query required' });
    }

    if (!SGO_API_KEY || !GROK_API_KEY) {
      return res.status(503).json({ error: 'Service temporarily unavailable' });
    }

    const token = ensureCookie(req, res);

    // Check if cookie already used free query
    if (hasUsedFreeQuery(token)) {
      return res.status(200).json({
        blocked: true,
        message: 'You\'ve used your free query for today. Sign up for unlimited access.',
      });
    }

    // Process the query
    const result = await handleSportsQuery(query.trim());

    // Mark cookie as used
    markTokenUsed(token);

    return res.json({
      blocked: false,
      data: result,
    });
  } catch (error) {
    console.error('Demo query error:', error);
    return res.status(500).json({ error: 'Query failed. Try again.' });
  }
});

// Check if user can query (for frontend pre-check)
router.get('/can-query', (req: Request, res: Response) => {
  const token = ensureCookie(req, res);
  const canQuery = !hasUsedFreeQuery(token);
  res.json({ canQuery });
});

export default router;
