import { FastifyInstance, FastifyRequest } from 'fastify';
import { prisma } from '../../../config/database';
import { requireAdminRole } from '../middleware/auth';
import { invalidateWordListCache } from '../services/word-filter.service';
import { logger } from '../../../utils/logger';

interface ListCommentsQuery {
  page?: string;
  limit?: string;
  status?: string; // 'pending' | 'safe' | 'flagged' | 'hidden'
  videoId?: string;
  search?: string;
  dateFrom?: string;
  dateTo?: string;
}

interface CommentIdParams {
  id: string;
}

interface HideCommentBody {
  reason?: 'manual' | 'word_filter' | 'spam' | 'link';
}

interface UpdateNotesBody {
  notes: string;
}

interface AddWordBody {
  word: string;
  level: 'low' | 'medium' | 'high' | 'custom';
}

interface WordFilterIdParams {
  id: string;
}

export async function commentAdminRoutes(fastify: FastifyInstance) {
  // All routes require admin role
  fastify.addHook('preHandler', requireAdminRole);

  /**
   * GET /admin/comments/stats
   * Counts by status (pending/flagged/hidden/total)
   */
  fastify.get(
    '/admin/comments/stats',
    async (_request, reply) => {
      try {
        const [total, pending, flagged, hidden, safe] = await Promise.all([
          prisma.comment.count(),
          prisma.comment.count({ where: { safetyStatus: 'pending' } }),
          prisma.comment.count({ where: { safetyStatus: 'flagged' } }),
          prisma.comment.count({ where: { isHidden: true } }),
          prisma.comment.count({ where: { safetyStatus: 'safe' } }),
        ]);

        return reply.send({ total, pending, flagged, hidden, safe });
      } catch (error) {
        logger.error('Failed to fetch comment stats:', error);
        return reply.code(500).send({ message: 'Failed to fetch comment stats' });
      }
    }
  );

  /**
   * GET /admin/comments
   * List all comments with filters, pagination, includes user + video title
   */
  fastify.get(
    '/admin/comments',
    async (
      request: FastifyRequest<{ Querystring: ListCommentsQuery }>,
      reply
    ) => {
      try {
        const page = parseInt(request.query.page || '1', 10);
        const limit = Math.min(parseInt(request.query.limit || '20', 10), 100);
        const skip = (page - 1) * limit;
        const { status, videoId, search, dateFrom, dateTo } = request.query;

        // Build where clause
        const where: any = {};

        if (status === 'hidden') {
          where.isHidden = true;
        } else if (status === 'pending' || status === 'safe' || status === 'flagged') {
          where.safetyStatus = status;
          where.isHidden = { not: true };
        }

        if (videoId) {
          const vid = parseInt(videoId, 10);
          if (!isNaN(vid)) where.mediaId = vid;
        }

        if (search) {
          where.content = { contains: search, mode: 'insensitive' };
        }

        if (dateFrom || dateTo) {
          where.createdAt = {};
          if (dateFrom) where.createdAt.gte = new Date(dateFrom);
          if (dateTo) where.createdAt.lte = new Date(dateTo);
        }

        const [comments, total] = await Promise.all([
          prisma.comment.findMany({
            where,
            include: {
              user: { select: { id: true, email: true, name: true } },
              media: { select: { id: true, filename: true } },
              moderation: {
                select: {
                  id: true,
                  status: true,
                  moderatedAt: true,
                  reason: true,
                  moderator: { select: { id: true, name: true } },
                },
              },
            },
            orderBy: { createdAt: 'desc' },
            take: limit,
            skip,
          }),
          prisma.comment.count({ where }),
        ]);

        const transformed = comments.map((c) => ({
          id: c.id,
          mediaId: c.mediaId,
          videoTitle: c.media.filename,
          content: c.content,
          createdAt: c.createdAt.toISOString(),
          safetyStatus: c.safetyStatus,
          safetyCategories: c.safetyCategories,
          safetyReasoning: c.safetyReasoning,
          isHidden: c.isHidden,
          hiddenAt: c.hiddenAt?.toISOString() ?? null,
          hiddenReason: c.hiddenReason,
          moderationNotes: c.moderationNotes,
          user: c.user
            ? { id: c.user.id, name: c.user.name || c.user.email, email: c.user.email }
            : null,
          moderation: c.moderation
            ? {
                id: c.moderation.id,
                status: c.moderation.status,
                moderatedAt: c.moderation.moderatedAt?.toISOString() ?? null,
                reason: c.moderation.reason,
                moderator: c.moderation.moderator
                  ? { id: c.moderation.moderator.id, name: c.moderation.moderator.name }
                  : null,
              }
            : null,
        }));

        return reply.send({
          comments: transformed,
          total,
          page,
          limit,
          totalPages: Math.ceil(total / limit),
        });
      } catch (error) {
        logger.error('Failed to fetch admin comments:', error);
        return reply.code(500).send({ message: 'Failed to fetch comments' });
      }
    }
  );

  /**
   * PATCH /admin/comments/:id/approve
   * Set safetyStatus to 'safe', create/update CommentModeration
   */
  fastify.patch(
    '/admin/comments/:id/approve',
    async (
      request: FastifyRequest<{ Params: CommentIdParams }>,
      reply
    ) => {
      try {
        const commentId = parseInt(request.params.id, 10);
        if (isNaN(commentId)) {
          return reply.code(400).send({ message: 'Invalid comment ID' });
        }

        const comment = await prisma.comment.findUnique({ where: { id: commentId } });
        if (!comment) {
          return reply.code(404).send({ message: 'Comment not found' });
        }

        await prisma.$transaction([
          prisma.comment.update({
            where: { id: commentId },
            data: {
              safetyStatus: 'safe',
              isHidden: false,
              safetyCheckedAt: new Date(),
            },
          }),
          prisma.commentModeration.upsert({
            where: { commentId },
            update: {
              status: 'approved',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
            },
            create: {
              commentId,
              status: 'approved',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
            },
          }),
        ]);

        return reply.send({ message: 'Comment approved' });
      } catch (error) {
        logger.error('Failed to approve comment:', error);
        return reply.code(500).send({ message: 'Failed to approve comment' });
      }
    }
  );

  /**
   * PATCH /admin/comments/:id/hide
   * Set isHidden to true, hiddenAt, hiddenReason, create CommentModeration
   */
  fastify.patch(
    '/admin/comments/:id/hide',
    async (
      request: FastifyRequest<{ Params: CommentIdParams; Body: HideCommentBody }>,
      reply
    ) => {
      try {
        const commentId = parseInt(request.params.id, 10);
        if (isNaN(commentId)) {
          return reply.code(400).send({ message: 'Invalid comment ID' });
        }

        const comment = await prisma.comment.findUnique({ where: { id: commentId } });
        if (!comment) {
          return reply.code(404).send({ message: 'Comment not found' });
        }

        const reason = request.body?.reason || 'manual';

        await prisma.$transaction([
          prisma.comment.update({
            where: { id: commentId },
            data: {
              isHidden: true,
              hiddenAt: new Date(),
              hiddenReason: reason,
            },
          }),
          prisma.commentModeration.upsert({
            where: { commentId },
            update: {
              status: 'rejected',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
              reason,
            },
            create: {
              commentId,
              status: 'rejected',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
              reason,
            },
          }),
        ]);

        return reply.send({ message: 'Comment hidden' });
      } catch (error) {
        logger.error('Failed to hide comment:', error);
        return reply.code(500).send({ message: 'Failed to hide comment' });
      }
    }
  );

  /**
   * PATCH /admin/comments/:id/unhide
   * Set isHidden to false, update CommentModeration to approved
   */
  fastify.patch(
    '/admin/comments/:id/unhide',
    async (
      request: FastifyRequest<{ Params: CommentIdParams }>,
      reply
    ) => {
      try {
        const commentId = parseInt(request.params.id, 10);
        if (isNaN(commentId)) {
          return reply.code(400).send({ message: 'Invalid comment ID' });
        }

        const comment = await prisma.comment.findUnique({ where: { id: commentId } });
        if (!comment) {
          return reply.code(404).send({ message: 'Comment not found' });
        }

        await prisma.$transaction([
          prisma.comment.update({
            where: { id: commentId },
            data: { isHidden: false },
          }),
          prisma.commentModeration.upsert({
            where: { commentId },
            update: {
              status: 'approved',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
            },
            create: {
              commentId,
              status: 'approved',
              moderatedBy: request.user!.id,
              moderatedAt: new Date(),
            },
          }),
        ]);

        return reply.send({ message: 'Comment unhidden' });
      } catch (error) {
        logger.error('Failed to unhide comment:', error);
        return reply.code(500).send({ message: 'Failed to unhide comment' });
      }
    }
  );

  /**
   * PUT /admin/comments/:id/notes
   * Update moderationNotes field
   */
  fastify.put(
    '/admin/comments/:id/notes',
    async (
      request: FastifyRequest<{ Params: CommentIdParams; Body: UpdateNotesBody }>,
      reply
    ) => {
      try {
        const commentId = parseInt(request.params.id, 10);
        if (isNaN(commentId)) {
          return reply.code(400).send({ message: 'Invalid comment ID' });
        }

        const { notes } = request.body || {};
        if (notes === undefined) {
          return reply.code(400).send({ message: 'Notes field is required' });
        }

        await prisma.comment.update({
          where: { id: commentId },
          data: { moderationNotes: notes },
        });

        return reply.send({ message: 'Notes updated' });
      } catch (error) {
        logger.error('Failed to update notes:', error);
        return reply.code(500).send({ message: 'Failed to update notes' });
      }
    }
  );

  /**
   * DELETE /admin/comments/:id
   * Hard delete comment + moderation record
   */
  fastify.delete(
    '/admin/comments/:id',
    async (
      request: FastifyRequest<{ Params: CommentIdParams }>,
      reply
    ) => {
      try {
        const commentId = parseInt(request.params.id, 10);
        if (isNaN(commentId)) {
          return reply.code(400).send({ message: 'Invalid comment ID' });
        }

        const comment = await prisma.comment.findUnique({ where: { id: commentId } });
        if (!comment) {
          return reply.code(404).send({ message: 'Comment not found' });
        }

        // Delete moderation record first (FK constraint), then comment
        await prisma.$transaction([
          prisma.commentModeration.deleteMany({ where: { commentId } }),
          prisma.comment.delete({ where: { id: commentId } }),
        ]);

        return reply.send({ message: 'Comment deleted' });
      } catch (error) {
        logger.error('Failed to delete comment:', error);
        return reply.code(500).send({ message: 'Failed to delete comment' });
      }
    }
  );

  // ========================================================================
  // WORD FILTER ADMIN ROUTES
  // ========================================================================

  /**
   * GET /admin/word-filters
   * List all words grouped by level
   */
  fastify.get(
    '/admin/word-filters',
    async (_request, reply) => {
      try {
        const words = await prisma.moderationWordList.findMany({
          orderBy: [{ level: 'desc' }, { word: 'asc' }],
          include: {
            creator: { select: { id: true, name: true } },
          },
        });

        return reply.send({ words });
      } catch (error) {
        logger.error('Failed to fetch word filters:', error);
        return reply.code(500).send({ message: 'Failed to fetch word filters' });
      }
    }
  );

  /**
   * POST /admin/word-filters
   * Add a word filter entry
   */
  fastify.post(
    '/admin/word-filters',
    async (
      request: FastifyRequest<{ Body: AddWordBody }>,
      reply
    ) => {
      try {
        const { word, level } = request.body || {};

        if (!word || !word.trim()) {
          return reply.code(400).send({ message: 'Word is required' });
        }

        if (!['low', 'medium', 'high', 'custom'].includes(level)) {
          return reply.code(400).send({ message: 'Level must be low, medium, high, or custom' });
        }

        // Check for duplicates
        const existing = await prisma.moderationWordList.findFirst({
          where: { word: { equals: word.trim(), mode: 'insensitive' } },
        });

        if (existing) {
          return reply.code(409).send({ message: 'Word already exists in filter list' });
        }

        const entry = await prisma.moderationWordList.create({
          data: {
            word: word.trim().toLowerCase(),
            level,
            createdBy: request.user!.id,
          },
        });

        invalidateWordListCache();

        return reply.code(201).send(entry);
      } catch (error) {
        logger.error('Failed to add word filter:', error);
        return reply.code(500).send({ message: 'Failed to add word filter' });
      }
    }
  );

  /**
   * DELETE /admin/word-filters/:id
   * Remove word from filter list
   */
  fastify.delete(
    '/admin/word-filters/:id',
    async (
      request: FastifyRequest<{ Params: WordFilterIdParams }>,
      reply
    ) => {
      try {
        const id = parseInt(request.params.id, 10);
        if (isNaN(id)) {
          return reply.code(400).send({ message: 'Invalid word filter ID' });
        }

        await prisma.moderationWordList.delete({ where: { id } });

        invalidateWordListCache();

        return reply.send({ message: 'Word filter removed' });
      } catch (error) {
        logger.error('Failed to delete word filter:', error);
        return reply.code(500).send({ message: 'Failed to delete word filter' });
      }
    }
  );
}
