const express = require('express');
const { authenticateToken } = require('../middleware/auth');
const db = require('../database');
const { getWebSocketManager } = require('../utils/websocket-manager');

const router = express.Router();

// Get vote history with filtering and pagination
router.get('/', (req, res) => {
  try {
    let { session_id, game_id, username, vote_type, page, limit } = req.query;

    page = parseInt(page) || 1;
    limit = Math.min(parseInt(limit) || 50, 100);
    if (page < 1) page = 1;
    if (limit < 1) limit = 50;
    const offset = (page - 1) * limit;

    const where = [];
    const params = [];

    if (session_id !== undefined) {
      const sid = parseInt(session_id);
      if (isNaN(sid)) {
        return res.status(400).json({ error: 'session_id must be an integer' });
      }
      where.push('lv.session_id = ?');
      params.push(sid);
    }

    if (game_id !== undefined) {
      const gid = parseInt(game_id);
      if (isNaN(gid)) {
        return res.status(400).json({ error: 'game_id must be an integer' });
      }
      where.push('lv.game_id = ?');
      params.push(gid);
    }

    if (username) {
      where.push('lv.username = ?');
      params.push(username);
    }

    if (vote_type !== undefined) {
      if (vote_type !== 'up' && vote_type !== 'down') {
        return res.status(400).json({ error: 'vote_type must be "up" or "down"' });
      }
      where.push('lv.vote_type = ?');
      params.push(vote_type === 'up' ? 1 : -1);
    }

    const whereClause = where.length > 0 ? 'WHERE ' + where.join(' AND ') : '';

    const countResult = db.prepare(
      `SELECT COUNT(*) as total FROM live_votes lv ${whereClause}`
    ).get(...params);

    const total = countResult.total;
    const total_pages = Math.ceil(total / limit) || 0;

    const votes = db.prepare(`
      SELECT
        lv.id,
        lv.session_id,
        lv.game_id,
        g.title AS game_title,
        g.pack_name,
        lv.username,
        CASE WHEN lv.vote_type = 1 THEN 'up' ELSE 'down' END AS vote_type,
        lv.timestamp,
        lv.created_at
      FROM live_votes lv
      JOIN games g ON lv.game_id = g.id
      ${whereClause}
      ORDER BY lv.timestamp DESC
      LIMIT ? OFFSET ?
    `).all(...params, limit, offset);

    res.json({
      votes,
      pagination: { page, limit, total, total_pages },
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Live vote endpoint - receives real-time votes from bot
router.post('/live', authenticateToken, (req, res) => {
  try {
    const { username, vote, timestamp, ticker } = req.body;

    // Validate payload
    if (!username || !vote || !timestamp) {
      return res.status(400).json({ 
        error: 'Missing required fields: username, vote, timestamp' 
      });
    }

    if (vote !== 'up' && vote !== 'down') {
      return res.status(400).json({ 
        error: 'vote must be either "up" or "down"' 
      });
    }

    // Validate timestamp format
    const voteTimestamp = new Date(timestamp);
    if (isNaN(voteTimestamp.getTime())) {
      return res.status(400).json({ 
        error: 'Invalid timestamp format. Use ISO 8601 format (e.g., 2025-11-01T20:30:00Z)' 
      });
    }

    // Check for active session
    const activeSession = db.prepare(`
      SELECT * FROM sessions WHERE is_active = 1 LIMIT 1
    `).get();

    if (!activeSession) {
      return res.status(404).json({ 
        error: 'No active session found' 
      });
    }

    let matchedGame = null;

    if (ticker) {
      // Ticker voting: resolve game globally by ticker symbol
      const game = db.prepare(`
        SELECT id AS game_id, title, pack_name, upvotes, downvotes, popularity_score
        FROM games WHERE ticker = ?
      `).get(ticker);

      if (!game) {
        return res.status(404).json({
          error: `Unknown ticker '${ticker}'`,
        });
      }

      matchedGame = game;
    } else {
      // thisgame++/thisgame-- voting: resolve game by timestamp interval
      const sessionGames = db.prepare(`
        SELECT sg.game_id, sg.played_at, g.title, g.pack_name, g.upvotes, g.downvotes, g.popularity_score
        FROM session_games sg
        JOIN games g ON sg.game_id = g.id
        WHERE sg.session_id = ?
        ORDER BY sg.played_at ASC
      `).all(activeSession.id);

      if (sessionGames.length === 0) {
        return res.status(404).json({ 
          error: 'No games have been played in the active session yet' 
        });
      }

      const voteTime = voteTimestamp.getTime();

      for (let i = 0; i < sessionGames.length; i++) {
        const currentGame = sessionGames[i];
        const nextGame = sessionGames[i + 1];
        
        const currentGameTime = new Date(currentGame.played_at).getTime();
        
        if (nextGame) {
          const nextGameTime = new Date(nextGame.played_at).getTime();
          if (voteTime >= currentGameTime && voteTime < nextGameTime) {
            matchedGame = currentGame;
            break;
          }
        } else {
          if (voteTime >= currentGameTime) {
            matchedGame = currentGame;
            break;
          }
        }
      }

      if (!matchedGame) {
        return res.status(404).json({ 
          error: 'Vote timestamp does not match any game in the active session',
          debug: {
            voteTimestamp: timestamp,
            sessionGames: sessionGames.map(g => ({
              title: g.title,
              played_at: g.played_at
            }))
          }
        });
      }
    }

    // Check for duplicate vote (within 1 second window)
    // Get the most recent vote from this user
    const lastVote = db.prepare(`
      SELECT timestamp FROM live_votes 
      WHERE username = ? 
      ORDER BY created_at DESC
      LIMIT 1
    `).get(username);

    if (lastVote) {
      const lastVoteTime = new Date(lastVote.timestamp).getTime();
      const currentVoteTime = new Date(timestamp).getTime();
      const timeDiffSeconds = Math.abs(currentVoteTime - lastVoteTime) / 1000;
      
      if (timeDiffSeconds <= 1) {
        return res.status(409).json({ 
          error: 'Duplicate vote detected (within 1 second of previous vote)',
          message: 'Please wait at least 1 second between votes',
          timeSinceLastVote: timeDiffSeconds
        });
      }
    }

    // Process the vote in a transaction
    const voteType = vote === 'up' ? 1 : -1;

    const insertVote = db.prepare(`
      INSERT INTO live_votes (session_id, game_id, username, vote_type, timestamp)
      VALUES (?, ?, ?, ?, ?)
    `);

    const updateUpvote = db.prepare(`
      UPDATE games 
      SET upvotes = upvotes + 1, popularity_score = popularity_score + 1 
      WHERE id = ?
    `);

    const updateDownvote = db.prepare(`
      UPDATE games 
      SET downvotes = downvotes + 1, popularity_score = popularity_score - 1 
      WHERE id = ?
    `);

    const processVote = db.transaction(() => {
      insertVote.run(activeSession.id, matchedGame.game_id, username, voteType, timestamp);
      
      if (voteType === 1) {
        updateUpvote.run(matchedGame.game_id);
      } else {
        updateDownvote.run(matchedGame.game_id);
      }
    });

    processVote();

    // Verify the live_votes row was persisted (diagnostic for production debugging)
    const voteCheck = db.prepare(
      'SELECT id FROM live_votes WHERE session_id = ? AND game_id = ? AND username = ? AND timestamp = ?'
    ).get(activeSession.id, matchedGame.game_id, username, timestamp);
    if (!voteCheck) {
      console.error('[votes] CRITICAL: live_votes INSERT committed but row not found', {
        session_id: activeSession.id, game_id: matchedGame.game_id, username, timestamp,
      });
    }

    // Get updated game stats
    const updatedGame = db.prepare(`
      SELECT id, title, upvotes, downvotes, popularity_score
      FROM games
      WHERE id = ?
    `).get(matchedGame.game_id);

    // Broadcast vote.received via WebSocket
    try {
      const wsManager = getWebSocketManager();
      if (wsManager) {
        wsManager.broadcastEvent('vote.received', {
          sessionId: activeSession.id,
          game: {
            id: updatedGame.id,
            title: updatedGame.title,
            pack_name: matchedGame.pack_name,
            ticker: ticker || undefined,
          },
          vote: {
            username: username,
            type: vote,
            timestamp: timestamp,
          },
          totals: {
            upvotes: updatedGame.upvotes,
            downvotes: updatedGame.downvotes,
            popularity_score: updatedGame.popularity_score,
          },
        }, activeSession.id);
      }
    } catch (wsError) {
      console.error('Error broadcasting vote.received event:', wsError);
    }

    // Get session stats
    const sessionStats = db.prepare(`
      SELECT 
        s.*,
        COUNT(sg.id) as games_played
      FROM sessions s
      LEFT JOIN session_games sg ON s.id = sg.session_id
      WHERE s.id = ?
      GROUP BY s.id
    `).get(activeSession.id);

    res.json({
      success: true,
      message: 'Vote recorded successfully',
      session: {
        id: sessionStats.id,
        games_played: sessionStats.games_played
      },
      game: {
        id: updatedGame.id,
        title: updatedGame.title,
        upvotes: updatedGame.upvotes,
        downvotes: updatedGame.downvotes,
        popularity_score: updatedGame.popularity_score
      },
      vote: {
        username: username,
        type: vote,
        timestamp: timestamp,
        ticker: ticker || undefined,
      }
    });

  } catch (error) {
    console.error('Error processing live vote:', error);
    res.status(500).json({ error: error.message });
  }
});

module.exports = router;

