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

interface ThreadsQuery {
  limit?: string;
  offset?: string;
}

export async function chatThreadsRoutes(fastify: FastifyInstance) {
  // All routes require authentication
  fastify.addHook('preHandler', authenticate);

  /**
   * GET /chat/threads
   * List videos where the authenticated user has commented,
   * ordered by latest activity, with unread counts.
   */
  fastify.get(
    '/chat/threads',
    async (
      request: FastifyRequest<{ Querystring: ThreadsQuery }>,
      reply
    ) => {
      try {
        const userId = request.user!.id;
        const limit = Math.min(parseInt(request.query.limit || '20', 10), 50);
        const offset = parseInt(request.query.offset || '0', 10);

        // Find distinct video IDs where user has commented
        const userVideoIds = await prisma.comment.findMany({
          where: { userId },
          select: { mediaId: true },
          distinct: ['mediaId'],
        });

        if (userVideoIds.length === 0) {
          return reply.send({ threads: [], total: 0 });
        }

        const mediaIds = userVideoIds.map((c) => c.mediaId);

        // Get the user's read statuses
        const readStatuses = await prisma.chatThreadReadStatus.findMany({
          where: { userId, mediaId: { in: mediaIds } },
        });
        const readStatusMap = new Map(readStatuses.map((r) => [r.mediaId, r.lastSeenAt]));

        // For each video, get latest comment and unread count
        const threads = await Promise.all(
          mediaIds.map(async (mediaId) => {
            const lastSeenAt = readStatusMap.get(mediaId);

            const [latestComment, totalComments, unreadCount, video] = await Promise.all([
              prisma.comment.findFirst({
                where: { mediaId, isHidden: { not: true } },
                orderBy: { createdAt: 'desc' },
                include: {
                  user: { select: { id: true, name: true, email: true } },
                },
              }),
              prisma.comment.count({
                where: { mediaId, isHidden: { not: true } },
              }),
              lastSeenAt
                ? prisma.comment.count({
                    where: {
                      mediaId,
                      isHidden: { not: true },
                      createdAt: { gt: lastSeenAt },
                    },
                  })
                : prisma.comment.count({
                    where: { mediaId, isHidden: { not: true } },
                  }),
              prisma.video.findUnique({
                where: { id: mediaId },
                select: { id: true, filename: true, thumbnailPath: true },
              }),
            ]);

            return {
              mediaId,
              videoTitle: video?.filename || `Video #${mediaId}`,
              thumbnailPath: video?.thumbnailPath || null,
              totalComments,
              unreadCount,
              lastActivity: latestComment?.createdAt.toISOString() || null,
              lastMessage: latestComment
                ? {
                    content: latestComment.content.length > 100
                      ? latestComment.content.substring(0, 100) + '...'
                      : latestComment.content,
                    userName: latestComment.user?.name || latestComment.user?.email || 'Anonymous',
                    createdAt: latestComment.createdAt.toISOString(),
                  }
                : null,
            };
          })
        );

        // Sort by lastActivity descending
        threads.sort((a, b) => {
          if (!a.lastActivity) return 1;
          if (!b.lastActivity) return -1;
          return new Date(b.lastActivity).getTime() - new Date(a.lastActivity).getTime();
        });

        // Paginate
        const paginated = threads.slice(offset, offset + limit);

        return reply.send({ threads: paginated, total: threads.length });
      } catch (error) {
        logger.error('Failed to fetch chat threads:', error);
        return reply.code(500).send({ message: 'Failed to fetch chat threads' });
      }
    }
  );

  /**
   * POST /chat/threads/:mediaId/read
   * Upsert ChatThreadReadStatus (lastSeenAt: now())
   */
  fastify.post(
    '/chat/threads/:mediaId/read',
    async (
      request: FastifyRequest<{ Params: { mediaId: string } }>,
      reply
    ) => {
      try {
        const userId = request.user!.id;
        const mediaId = parseInt(request.params.mediaId, 10);

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

        // Find existing read status by unique index
        const existing = await prisma.chatThreadReadStatus.findFirst({
          where: { userId, mediaId },
        });

        if (existing) {
          await prisma.chatThreadReadStatus.update({
            where: { id: existing.id },
            data: { lastSeenAt: new Date() },
          });
        } else {
          await prisma.chatThreadReadStatus.create({
            data: { userId, mediaId, lastSeenAt: new Date() },
          });
        }

        return reply.send({ message: 'Thread marked as read' });
      } catch (error) {
        logger.error('Failed to mark thread as read:', error);
        return reply.code(500).send({ message: 'Failed to mark thread as read' });
      }
    }
  );
}
