import { FastifyInstance } from 'fastify';
import { prisma } from '../../../config/database';
import { authenticate } from '../middleware/auth';
import { broadcastReactionToVideo } from './chat-stream.routes.js';

// Rebranded reaction emojis (6 standard social reactions)
const REACTION_EMOJIS: Record<string, string> = {
  like: '👍',
  love: '❤️',
  laugh: '😂',
  wow: '😮',
  sad: '😢',
  angry: '😠',
};

// Cooldown tracking: userId+type -> lastTimestamp
const reactionCooldowns = new Map<string, number>();
const COOLDOWN_SECONDS = 30;

// Format video timestamp as MM:SS or H:MM:SS
function formatVideoTime(seconds: number): string {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;

  if (h > 0) {
    return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
  }
  return `${m}:${s.toString().padStart(2, '0')}`;
}

interface AddReactionBody {
  mediaId: number;
  reactionType: string;
  videoTimestamp: number;
}

interface GetReactionsQuery {
  mediaId?: string;
  userId?: string;
  limit?: string;
}

export async function reactionsRoutes(fastify: FastifyInstance) {
  // Add reaction (authenticated users only)
  fastify.post<{ Body: AddReactionBody }>(
    '/',
    {
      preHandler: authenticate,
    },
    async (request, reply) => {
      const { mediaId, reactionType, videoTimestamp } = request.body;
      const userId = request.user!.id;

      // Validate reaction type
      if (!REACTION_EMOJIS[reactionType]) {
        return reply.code(400).send({ message: 'Invalid reaction type' });
      }

      // Check cooldown
      const cooldownKey = `${userId}:${reactionType}`;
      const now = Date.now();
      const lastReactionTime = reactionCooldowns.get(cooldownKey);
      if (lastReactionTime) {
        const timeSinceLastReaction = (now - lastReactionTime) / 1000;
        if (timeSinceLastReaction < COOLDOWN_SECONDS) {
          const cooldownRemaining = Math.ceil(COOLDOWN_SECONDS - timeSinceLastReaction);
          return reply.code(429).send({
            message: `Please wait ${cooldownRemaining}s before reacting again`,
            cooldownEndsAt: new Date(lastReactionTime + COOLDOWN_SECONDS * 1000).toISOString(),
          });
        }
      }

      // Check if video exists
      const video = await prisma.video.findUnique({
        where: { id: mediaId },
      });

      if (!video) {
        return reply.code(404).send({ message: 'Video not found' });
      }

      // Update cooldown
      reactionCooldowns.set(cooldownKey, now);

      // Create reaction
      const reaction = await prisma.videoReaction.create({
        data: {
          mediaId,
          userId,
          reactionType: reactionType as any, // Cast string to ReactionType enum
          videoTimestamp,
          createdAt: new Date(),
        },
        include: {
          user: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
      });

      // Broadcast to SSE subscribers
      const broadcastData = {
        id: reaction.id,
        reactionType: reaction.reactionType,
        emoji: REACTION_EMOJIS[reactionType],
        videoTimestamp: reaction.videoTimestamp,
        formattedTime: formatVideoTime(videoTimestamp),
        createdAt: reaction.createdAt.toISOString(),
        user: reaction.user
          ? {
              id: reaction.user.id,
              name: reaction.user.name || reaction.user.email,
            }
          : null,
      };

      broadcastReactionToVideo(mediaId, broadcastData);

      return {
        success: true,
        reaction: broadcastData,
      };
    }
  );

  // Get reactions
  fastify.get<{ Querystring: GetReactionsQuery }>(
    '/',
    async (request, reply) => {
      const { mediaId, userId, limit = '50' } = request.query;

      const where: any = {};

      // Filter by mediaId if provided
      if (mediaId) {
        where.mediaId = parseInt(mediaId);
      }

      // Filter by userId if provided
      if (userId) {
        where.userId = userId;
      }

      const reactions = await prisma.videoReaction.findMany({
        where,
        orderBy: {
          createdAt: 'desc',
        },
        take: parseInt(limit),
      });

      // Enhance with emojis and formatted times
      const enhancedReactions = reactions.map(r => ({
        ...r,
        emoji: REACTION_EMOJIS[r.reactionType] || '❓',
        formattedTime: formatVideoTime(r.videoTimestamp),
      }));

      return {
        reactions: enhancedReactions,
      };
    }
  );

  // Get reaction config (returns available reactions)
  fastify.get('/config', async (request, reply) => {
    return {
      reactions: Object.entries(REACTION_EMOJIS).map(([type, emoji]) => ({
        type,
        emoji,
        label: type.charAt(0).toUpperCase() + type.slice(1),
      })),
    };
  });

  // Get reactions for chat timeline (non-aggregated, for display in chat)
  fastify.get<{
    Params: { mediaId: string };
    Querystring: { limit?: string };
  }>(
    '/:mediaId/chat',
    async (request, reply) => {
      const mediaId = parseInt(request.params.mediaId, 10);
      const limit = parseInt(request.query.limit || '500', 10);

      if (isNaN(mediaId)) {
        return reply.code(400).send({ message: 'Invalid media ID' });
      }

      const reactions = await prisma.videoReaction.findMany({
        where: { mediaId },
        include: {
          user: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
        orderBy: {
          createdAt: 'asc',
        },
        take: limit,
      });

      // Transform for chat timeline
      const transformedReactions = reactions.map((r) => ({
        id: r.id,
        type: 'reaction' as const,
        reactionType: r.reactionType,
        emoji: REACTION_EMOJIS[r.reactionType] || '❓',
        videoTimestamp: r.videoTimestamp,
        formattedTime: formatVideoTime(r.videoTimestamp),
        createdAt: r.createdAt.toISOString(),
        user: r.user
          ? {
              id: r.user.id,
              name: r.user.name || r.user.email,
            }
          : null,
      }));

      return {
        reactions: transformedReactions,
      };
    }
  );

  /**
   * Cleanup cooldown map periodically (every 5 minutes)
   */
  setInterval(() => {
    const now = Date.now();
    for (const [key, timestamp] of reactionCooldowns.entries()) {
      if (now - timestamp > COOLDOWN_SECONDS * 1000) {
        reactionCooldowns.delete(key);
      }
    }
  }, 5 * 60 * 1000);
}
