import { router, protectedProcedure, publicProcedure } from '../_core/trpc.js.ts';
import { z } from 'zod';
import TournamentWebSocketService from '../tournamentWebSocketService.js';

const tournamentWebSocketService = new TournamentWebSocketService();

export const tournamentWebSocketRouter = router({
  /**
   * Subscribe to real-time tournament updates
   */
  subscribeTournamentUpdates: protectedProcedure
    .input(z.object({ tournamentId: z.string() }))
    .subscription(async function* ({ input, ctx }) {
      const { tournamentId } = input;
      const playerId = ctx.user.id;

      // Register player for tournament
      tournamentWebSocketService.registerPlayerJoin(tournamentId, {
        playerId,
        playerName: ctx.user.name || 'Anonymous',
        score: 0,
        rank: 1,
      });

      // Create event listener for updates
      const handleUpdate = (update: any) => {
        if (update.tournamentId === tournamentId) {
          yield update;
        }
      };

      tournamentWebSocketService.on('batch_updates', handleUpdate);

      try {
        // Keep subscription alive
        await new Promise(() => {});
      } finally {
        tournamentWebSocketService.removeListener('batch_updates', handleUpdate);
        tournamentWebSocketService.registerPlayerLeave(tournamentId, playerId);
      }
    }),

  /**
   * Get current leaderboard for tournament
   */
  getLeaderboard: publicProcedure
    .input(z.object({ tournamentId: z.string() }))
    .query(({ input }) => {
      return tournamentWebSocketService.getLeaderboard(input.tournamentId);
    }),

  /**
   * Get player position in tournament
   */
  getPlayerPosition: protectedProcedure
    .input(z.object({ tournamentId: z.string() }))
    .query(({ input, ctx }) => {
      return tournamentWebSocketService.getPlayerPosition(input.tournamentId, ctx.user.id);
    }),

  /**
   * Update player score
   */
  updateScore: protectedProcedure
    .input(
      z.object({
        tournamentId: z.string(),
        scoreIncrease: z.number().positive(),
      })
    )
    .mutation(({ input, ctx }) => {
      tournamentWebSocketService.updatePlayerScore(
        input.tournamentId,
        ctx.user.id,
        input.scoreIncrease
      );

      return { success: true };
    }),

  /**
   * Get tournament statistics
   */
  getTournamentStats: publicProcedure
    .input(z.object({ tournamentId: z.string() }))
    .query(({ input }) => {
      return tournamentWebSocketService.getTournamentStats(input.tournamentId);
    }),

  /**
   * Get player's active tournaments
   */
  getPlayerTournaments: protectedProcedure.query(({ ctx }) => {
    return tournamentWebSocketService.getPlayerTournaments(ctx.user.id);
  }),

  /**
   * End tournament and get final rankings
   */
  endTournament: protectedProcedure
    .input(z.object({ tournamentId: z.string() }))
    .mutation(({ input }) => {
      return tournamentWebSocketService.endTournament(input.tournamentId);
    }),

  /**
   * Get rank change events for player
   */
  onRankChanged: protectedProcedure
    .input(z.object({ tournamentId: z.string() }))
    .subscription(async function* ({ input, ctx }) {
      const { tournamentId } = input;
      const playerId = ctx.user.id;

      const handleRankChange = (data: any) => {
        if (data.tournamentId === tournamentId && data.playerId === playerId) {
          yield data;
        }
      };

      tournamentWebSocketService.on('rank_changed', handleRankChange);

      try {
        await new Promise(() => {});
      } finally {
        tournamentWebSocketService.removeListener('rank_changed', handleRankChange);
      }
    }),

  /**
   * Get score update events
   */
  onScoreUpdated: protectedProcedure
    .input(z.object({ tournamentId: z.string() }))
    .subscription(async function* ({ input, ctx }) {
      const { tournamentId } = input;
      const playerId = ctx.user.id;

      const handleScoreUpdate = (data: any) => {
        if (data.tournamentId === tournamentId && data.playerId === playerId) {
          yield data;
        }
      };

      tournamentWebSocketService.on('score_updated', handleScoreUpdate);

      try {
        await new Promise(() => {});
      } finally {
        tournamentWebSocketService.removeListener('score_updated', handleScoreUpdate);
      }
    }),

  /**
   * Get player join/leave events
   */
  onPlayerActivity: publicProcedure
    .input(z.object({ tournamentId: z.string() }))
    .subscription(async function* ({ input }) {
      const { tournamentId } = input;

      const handlePlayerJoined = function*(data: any) {
        if (data.tournamentId === tournamentId) {
          yield { type: 'joined', ...data };
        }
      };

      const handlePlayerLeft = function*(data: any) {
        if (data.tournamentId === tournamentId) {
          yield { type: 'left', ...data };
        }
      };

      tournamentWebSocketService.on('player_joined', handlePlayerJoined);
      tournamentWebSocketService.on('player_left', handlePlayerLeft);

      try {
        await new Promise(() => {});
      } finally {
        tournamentWebSocketService.removeListener('player_joined', handlePlayerJoined);
        tournamentWebSocketService.removeListener('player_left', handlePlayerLeft);
      }
    }),

  /**
   * Get tournament end event
   */
  onTournamentEnd: publicProcedure
    .input(z.object({ tournamentId: z.string() }))
    .subscription(async function* ({ input }) {
      const { tournamentId } = input;

      const handleTournamentEnd = (data: any) => {
        if (data.tournamentId === tournamentId) {
          yield data;
        }
      };

      tournamentWebSocketService.on('tournament_ended', handleTournamentEnd);

      try {
        await new Promise(() => {});
      } finally {
        tournamentWebSocketService.removeListener('tournament_ended', handleTournamentEnd);
      }
    }),
});

export default tournamentWebSocketRouter;
