import express from 'express';
import * as Poker from 'poker-engine';

const app = express();
app.use(express.json());

// Database operations (stubbed)
function loadGameHand(gameId: string): Poker.Hand | null {
  // TODO: Load the Hand from database by gameId
  // The 'log' JSONB field contains the actions array
  // const result = await db.query('SELECT * FROM games WHERE id = $1', [gameId]);
  // const game = result.rows[0];
  // return {
  //   actions: game.log,  // log contains the actions array
  //   variant: game.variant,
  //   seed: game.seed,
  //   // ... construct other Hand properties from game metadata
  // };
  return null;
}

function saveGameHand(gameId: string, hand: Poker.Hand): void {
  // TODO: Save the Hand to database and update timeout
  // The 'log' JSONB field stores the actions array
  // const game = Poker.Game.create(hand);
  // const timeoutAt = new Date(Date.now() + game.timeLimit * 1000);
  // await db.query('UPDATE games SET log = $1, timeout_at = $2 WHERE id = $3', [hand.actions, timeoutAt, gameId]);
}

function broadcastToPlayers(gameId: string, game: Poker.Game): void {
  // TODO: Send sanitized hands to each player
  // const players = getPlayersInGame(gameId);
  // for (const playerId of players) {
  //   const sanitizedHand = Poker.Game.export(game, playerId);
  //   websocket.send(playerId, { gameId, hand: sanitizedHand });
  // }
}

/**
 * Single endpoint for poker game state management
 * Follows the stateless request-response pattern described in the spec
 */
app.post('/game/poker', async (req, res) => {
  try {
    // Step 1: Receiving - Request body IS the Hand from the client
    const clientHand: Poker.Hand = req.body;

    if (!clientHand) {
      return res.status(400).json({ error: 'Missing hand data' });
    }

    // Step 2: Loading - Load current hand from database
    const serverHand = loadGameHand(clientHand.id);

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

    // Step 3: Merging - Merge client hand with server hand
    const mergedHand = Poker.Hand.merge(serverHand, clientHand);

    // Step 4: Applying - Create game (which applies all actions from the merged Hand)
    let game = Poker.Game.create(mergedHand);

    // Check and execute dealer actions if needed (flop, turn, river, showdown)
    game = Poker.Game.advance(game);

    // Step 5: Storing - Save updated hand to database
    const updatedHand = Poker.Game.export(game);
    saveGameHand(clientHand.id, updatedHand);

    // Step 6: Sanitizing & Updating - Broadcast sanitized hands to all players
    broadcastToPlayers(clientHand.id, game);

    // Return the sanitized hand for the requesting player
    // not strictly necessary, as typically client will receieve it in the websocket message
    const responseHand = Poker.Game.export(game, Poker.Game.getAuthorPlayerIndex(game));

    res.json(responseHand);
  } catch (error) {
    console.error('Error processing poker action:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

/**
 * Check for expired game timeouts and apply fold actions
 * This function should be called periodically (e.g., every second)
 */
async function checkGameTimeouts(): Promise<void> {
  const expiredGames = await db.query(
    'SELECT id FROM games WHERE timeout_at < NOW() AND timeout_at IS NOT NULL'
  );
  for (const row of expiredGames.rows) {
    const gameId = row.id;

    // Load the current game state
    const hand = loadGameHand(gameId);
    if (!hand) continue;

    const game = Poker.Game.create(hand);
    const activePlayerIndex = Poker.Game.getActivePlayer(game);

    if (activePlayerIndex !== -1) {
      // Apply fold action for the timed-out player
      const foldAction = Poker.Game.act(game, 'fold', activePlayerIndex);
      const updatedGame = Poker.Game.applyAction(game, foldAction);

      // Check and execute dealer actions if needed
      const finalGame = Poker.Game.advance(updatedGame);

      // Save updated state (which also updates timeout)
      const updatedHand = Poker.Game.export(finalGame);
      saveGameHand(gameId, updatedHand);

      // Broadcast to all players
      broadcastToPlayers(gameId, finalGame);
    }
  }
}

/**
 * Start timeout polling - runs every second
 * This would typically be a separate process/service
 */
setInterval(() => {
  checkGameTimeouts();
}, 1000);

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Poker game server running on port ${PORT}`);
});

export default app;
