import express from 'express';
import { Request, Response } from 'express';
import { getLobby, getLobbyByCode, pool } from '../config/db';
import { createLogger } from '../utils/logger';
import eventService from '../services/eventService';
import gameService from '../services/gameService';
import { LobbyPlayer } from '../models/LobbyPlayers';

const router = express.Router();
const logger = createLogger('gameRoutes');

router.post('/:code/continue', async (req: Request, res: Response) => {
  const { code } = req.params;

  const currentState = await gameService.getLobbyState(code);
  const lobby = await getLobbyByCode(code);

  
  if (!lobby) {
    res.status(404).json({ error: 'Lobby not found' });
    return;
  }
  logger.info(`Fetched lobby123:`, lobby);

  if (currentState.questionsRemaining <= 0) {
    eventService.emitLobbyEvent(code, {
      type: 'game_finished',
      lobbyCode: code,
      timestamp: new Date().toISOString(),
    });

    return;
  }

  // Pass the lobby's tags array to getRandomQuestion
  const question = await gameService.getRandomQuestion(lobby.tags);

  logger.info(`Fetched question:`, question);

  currentState.currentQuestion = question;
  currentState.timer = lobby?.secondsPerRound ?? 15;

  if (currentState.questionsRemaining === undefined) {
    currentState.questionsRemaining = lobby?.numberOfQuestions ?? 10;
  } else {
    currentState.questionsRemaining -= 1;
  }

  currentState.state = 'question';
  currentState.currentQuestionIndex += 1;

  await gameService.updateLobbyState(code, currentState);

  currentState.currentQuestion.answer = ["******"];

  eventService.emitLobbyEvent(code, {
    type: 'next_question',
    lobbyCode: code,
    timestamp: new Date().toISOString(),
    state: currentState,
  });

  res.status(200).json({ message: 'Next question event emitted successfully' });
});

router.post('/:code/answer', async (req: Request, res: Response) => {
  const userId = req.body.userId;

  const { code } = req.params;
  const currentState = await gameService.getLobbyState(code);
  const lobby = await getLobbyByCode(code);

  if (!lobby) {
    return;
  }

  if (currentState.state === 'correct') {
    return;
  }

  const correctAnswers = currentState.currentQuestion.answer;
  const userAnswer = req.body.answer.toLowerCase();
  const currentTimer = req.body.currentTimer;

  // Check if user's answer matches any of the possible answers (case insensitive)
  if (Array.isArray(correctAnswers) && correctAnswers.some(ans => ans.toLowerCase() === userAnswer)) {
    const points = gameService.calculatePoints(currentTimer, lobby.secondsPerRound ?? 15);
    const newScore = await gameService.updatePointsForPlayer(code, userId, points);

    currentState.state = 'correct';
    await gameService.updateLobbyState(code, currentState);

    if (newScore >= lobby.pointsToWin) {
      eventService.emitLobbyEvent(code, {
        type: 'game_finished',
        lobbyCode: code,
        timestamp: new Date().toISOString(),
      });
      return;
    }

    const correctState = {
      correctUserId: userId,
      correctAnswer: correctAnswers[0], // Send back the primary/canonical answer for display
    };

    eventService.emitLobbyEvent(code, {
      type: 'question_correct',
      lobbyCode: code,
      timestamp: new Date().toISOString(),
      state: correctState,
    });
  }

  res.status(200).send();
});

router.post('/:code/timeout', async (req: Request, res: Response) => {
  const { code } = req.params;
  const currentState = await gameService.getLobbyState(code);

  const correctAnswer = currentState.currentQuestion.answer[0]; // Use the first answer

  const correctState = {
    correctUserId: null,
    correctAnswer: correctAnswer,
  };

  eventService.emitLobbyEvent(code, {
    type: 'question_timeout',
    lobbyCode: code,
    timestamp: new Date().toISOString(),
    state: correctState,
  });

  res.status(200).send();
});

router.get('/:code/events', async (req: Request, res: Response) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.setHeader('X-Accel-Buffering', 'no');

  try {
    const { code } = req.params;
    logger.info(`New client connecting to events for lobby ${code}`);

    const lobby = await getLobby(code);
    if (!lobby) {
      throw new Error('Lobby not found');
    }

    const removeClient = eventService.addLobbyClient(code, res);
    logger.info(`👥 Client connected to lobby ${code}`);

    res.write(
      `data: ${JSON.stringify({ type: 'connected', message: 'Event stream connected' })}\n\n`
    );

    const heartbeatInterval = setInterval(() => {
      if (!res.writableEnded) {
        res.write(`:heartbeat\n\n`);
      } else {
        clearInterval(heartbeatInterval);
      }
    }, 30000);

    const sendEvent = (event: string) => {
      try {
        if (!res.writableEnded) {
          logger.info(`📨 Sending lobby event to client:`, event);
          res.write(`data: ${event}\n\n`);
        }
      } catch (err) {
        logger.error('❌ Error sending event to client:', err);
      }
    };

    const removeListener = eventService.onLobbyEvent(code, sendEvent);

    eventService.emitLobbyEvent(code, {
      type: 'game_started',
      lobbyCode: code,
      timestamp: new Date().toISOString(),
    });

    req.on('close', () => {
      logger.info(`Client disconnected from lobby ${code} events`);
      clearInterval(heartbeatInterval);
      removeClient();
      removeListener();
    });
  } catch (err: unknown) {
    const error = err as Error;
    logger.error('🔥 Error setting up lobby event stream:', error.stack);
    if (!res.headersSent) {
      res.status(500).json({ error: 'Failed to set up event stream' });
    }
  }
});

// Fetch players with scores for a specific lobby
router.get('/:code/players', async (req: Request, res: Response): Promise<void> => {
  const { code } = req.params;
  try {
    logger.info(`Fetching players for lobby: ${code}`);
    const lobby = await getLobbyByCode(code);

    if (!lobby) {
      res.status(404).json({ error: 'Lobby not found' });
      return;
    }

    logger.info(`Lobby found:`, lobby);

    // Get all players in the lobby with their scores
    const lobby_player = await pool.query<LobbyPlayer>(
      `
        SELECT player.id, player.name, lobby_players.score
        FROM player
        JOIN lobby_players ON player.id = lobby_players.player
        WHERE lobby_players.lobby = $1
      `,
      [code]
    );

    const lobbyPlayers = lobby_player.rows as LobbyPlayer[];
    logger.info(`Found ${lobbyPlayers.length} players in lobby ${code}`);
    res.json(lobbyPlayers);
  } catch (err) {
    logger.error(`Error fetching players for lobby ${code}:`, err);
    res.status(500).json({ error: 'Internal Server Error' });
  }
});

export default router;
