import { protectedProcedure, publicProcedure, router } from '../_core/trpc.ts';
import { z } from 'zod';
import { getWebSocketManager } from '../websocket.ts';
import { seasonalEventsManager } from '../seasonalEvents.ts';
import { leaderboardsManager } from '../leaderboards.ts';

export const realtimeRouter = router({
  // ===== WEBSOCKET PROCEDURES =====

  // Get WebSocket connection stats
  getWebSocketStats: publicProcedure.query(async () => {
    const wsManager = getWebSocketManager();
    return wsManager.getStats();
  }),

  // Check if user is online
  isUserOnline: publicProcedure
    .input(z.object({ userId: z.number() }))
    .query(async ({ input }) => {
      const wsManager = getWebSocketManager();
      return { isOnline: wsManager.isUserOnline(input.userId) };
    }),

  // Get multiple users' online status
  getUsersOnlineStatus: publicProcedure
    .input(z.object({ userIds: z.array(z.number()) }))
    .query(async ({ input }) => {
      const wsManager = getWebSocketManager();
      const statuses: Record<number, boolean> = {};

      for (const userId of input.userIds) {
        statuses[userId] = wsManager.isUserOnline(userId);
      }

      return statuses;
    }),

  // ===== SEASONAL EVENTS PROCEDURES =====

  // Get current active event
  getCurrentEvent: publicProcedure.query(async () => {
    const event = seasonalEventsManager.getCurrentEvent();
    return event;
  }),

  // Get all events
  getAllEvents: publicProcedure.query(async () => {
    const events = seasonalEventsManager.getAllEvents();
    return events;
  }),

  // Get events by status
  getEventsByStatus: publicProcedure
    .input(z.object({ status: z.enum(['upcoming', 'active', 'ended']) }))
    .query(async ({ input }) => {
      const events = seasonalEventsManager.getEventsByStatus(input.status);
      return events;
    }),

  // Get events by type
  getEventsByType: publicProcedure
    .input(z.object({ type: z.enum(['seasonal', 'holiday', 'special', 'anniversary']) }))
    .query(async ({ input }) => {
      const events = seasonalEventsManager.getEventsByType(input.type);
      return events;
    }),

  // Participate in event
  participateInEvent: protectedProcedure
    .input(z.object({ eventId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const result = await seasonalEventsManager.participateInEvent(ctx.user.id, input.eventId);
      return result;
    }),

  // Get player event progress
  getPlayerEventProgress: protectedProcedure
    .input(z.object({ eventId: z.string() }))
    .query(async ({ ctx, input }) => {
      const progress = await seasonalEventsManager.getPlayerEventProgress(ctx.user.id, input.eventId);
      return progress;
    }),

  // Get all player event progress
  getPlayerAllEventProgress: protectedProcedure.query(async ({ ctx }) => {
    const progress = await seasonalEventsManager.getPlayerAllEventProgress(ctx.user.id);
    return progress;
  }),

  // Claim event rewards
  claimEventRewards: protectedProcedure
    .input(z.object({ eventId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const result = await seasonalEventsManager.claimRewards(ctx.user.id, input.eventId);
      return result;
    }),

  // Get event leaderboard
  getEventLeaderboard: publicProcedure
    .input(z.object({ eventId: z.string(), limit: z.number().default(100) }))
    .query(async ({ input }) => {
      const leaderboard = await seasonalEventsManager.getEventLeaderboard(input.eventId, input.limit);
      return leaderboard;
    }),

  // Get event stats
  getEventStats: publicProcedure
    .input(z.object({ eventId: z.string() }))
    .query(async ({ input }) => {
      const stats = await seasonalEventsManager.getEventStats(input.eventId);
      return stats;
    }),

  // ===== LEADERBOARDS PROCEDURES =====

  // Get leaderboard
  getLeaderboard: publicProcedure
    .input(
      z.object({
        type: z.enum(['achievements', 'challenges', 'events', 'referrals', 'winnings', 'playtime']),
        period: z.enum(['daily', 'weekly', 'monthly', 'alltime']),
        limit: z.number().default(100),
      })
    )
    .query(async ({ input }) => {
      const leaderboard = await leaderboardsManager.getLeaderboard(input.type, input.period, input.limit);
      return leaderboard;
    }),

  // Get player rank
  getPlayerRank: protectedProcedure
    .input(
      z.object({
        type: z.enum(['achievements', 'challenges', 'events', 'referrals', 'winnings', 'playtime']),
        period: z.enum(['daily', 'weekly', 'monthly', 'alltime']),
      })
    )
    .query(async ({ ctx, input }) => {
      const rank = await leaderboardsManager.getPlayerRank(ctx.user.id, input.type, input.period);
      return rank;
    }),

  // Get player leaderboard stats
  getPlayerLeaderboardStats: protectedProcedure.query(async ({ ctx }) => {
    const stats = await leaderboardsManager.getPlayerStats(ctx.user.id);
    return stats;
  }),

  // Get top players
  getTopPlayers: publicProcedure
    .input(z.object({ limit: z.number().default(10) }))
    .query(async ({ input }) => {
      const topPlayers = await leaderboardsManager.getTopPlayers(input.limit);
      return topPlayers;
    }),

  // Get leaderboard history
  getLeaderboardHistory: protectedProcedure
    .input(
      z.object({
        type: z.enum(['achievements', 'challenges', 'events', 'referrals', 'winnings', 'playtime']),
        periods: z.array(z.enum(['daily', 'weekly', 'monthly', 'alltime'])).optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const history = await leaderboardsManager.getLeaderboardHistory(
        input.type,
        ctx.user.id,
        input.periods
      );
      return history;
    }),

  // Get trending players
  getTrendingPlayers: publicProcedure
    .input(z.object({ limit: z.number().default(10) }))
    .query(async ({ input }) => {
      const trending = await leaderboardsManager.getTrendingPlayers(input.limit);
      return trending;
    }),

  // Get leaderboard categories
  getLeaderboardCategories: publicProcedure.query(async () => {
    const categories = leaderboardsManager.getLeaderboardCategories();
    return categories;
  }),

  // Get leaderboard stats
  getLeaderboardStats: publicProcedure.query(async () => {
    const stats = leaderboardsManager.getStats();
    return stats;
  }),

  // Update leaderboards (admin only)
  updateLeaderboards: protectedProcedure.mutation(async ({ ctx }) => {
    if (ctx.user.role !== 'admin') {
      throw new Error('Unauthorized');
    }

    await leaderboardsManager.updateLeaderboards();
    return { success: true, message: 'Leaderboards updated' };
  }),
});
