import { FastifyInstance, FastifyRequest } from 'fastify';
import { prisma } from '../../../config/database';
import { logger } from '../../../utils/logger';

/**
 * Public upvote routes for media gallery
 * Uses X-Session-ID header for anonymous upvote tracking
 */
export async function upvoteRoutes(fastify: FastifyInstance) {
  /**
   * POST /public/:id/upvote
   * Toggle upvote for a video (session-based, no auth required)
   */
  fastify.post(
    '/public/:id/upvote',
    async (request: FastifyRequest<{ Params: { id: string }; Body: { sessionId?: string } }>, reply) => {
      const videoId = parseInt(request.params.id);
      const sessionId = (request.headers['x-session-id'] as string) || request.body?.sessionId;

      if (!sessionId) {
        return reply.code(400).send({ message: 'Session ID required (X-Session-ID header or body.sessionId)' });
      }

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

      // Verify video exists and is published
      const video = await prisma.video.findFirst({
        where: { id: videoId, isPublished: true, isLocked: false },
        select: { id: true, upvoteCount: true },
      });

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

      // Ensure session record exists
      await prisma.session.upsert({
        where: { id: sessionId },
        create: {
          id: sessionId,
          ipAddress: request.ip,
          userAgent: request.headers['user-agent'] || null,
          firstSeenAt: new Date(),
          lastSeenAt: new Date(),
        },
        update: {
          lastSeenAt: new Date(),
        },
      });

      // Check if already upvoted
      const existing = await prisma.upvote.findFirst({
        where: { mediaId: videoId, sessionId },
      });

      let upvoted: boolean;
      let newCount: number;

      if (existing) {
        // Remove upvote
        await prisma.upvote.delete({ where: { id: existing.id } });
        newCount = Math.max(0, video.upvoteCount - 1);
        upvoted = false;
      } else {
        // Add upvote
        await prisma.upvote.create({
          data: { mediaId: videoId, sessionId },
        });
        newCount = video.upvoteCount + 1;
        upvoted = true;
      }

      // Update denormalized count on video
      await prisma.video.update({
        where: { id: videoId },
        data: { upvoteCount: newCount },
      });

      logger.info(`Upvote ${upvoted ? 'added' : 'removed'} for video ${videoId}`, { sessionId: sessionId.substring(0, 8) });

      return { upvoted, upvoteCount: newCount };
    }
  );

  /**
   * GET /public/:id/upvote-status
   * Check if session has upvoted a video
   */
  fastify.get(
    '/public/:id/upvote-status',
    async (request: FastifyRequest<{ Params: { id: string }; Querystring: { sessionId?: string } }>, reply) => {
      const videoId = parseInt(request.params.id);
      const sessionId = (request.headers['x-session-id'] as string) || request.query.sessionId;

      if (!sessionId) {
        return { upvoted: false };
      }

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

      const upvote = await prisma.upvote.findFirst({
        where: { mediaId: videoId, sessionId },
      });

      return { upvoted: !!upvote };
    }
  );
}
