/**
 * @copyright NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */
import type { FastifyPluginAsync } from "fastify";
import type {
  CreateCommentReportDto,
  CommentReportWithDetails,
  ReportStatus,
  UpdateCommentReportDto,
} from "@library/shared-types";
import { ReportReason, AchievementCategory } from "@library/shared-types";

import { CommentReportService } from "../../services/comment-report.service.js";
import { AchievementService } from "../../services/achievement.service";
import { adminGuard } from "../../middleware/admin-guard.js";

const commentReportsRoutes: FastifyPluginAsync = async (fastify) => {
  const commentReportService = new CommentReportService();

  // Create a new comment report (authenticated users)
  fastify.post<{
    Body: CreateCommentReportDto;
    Reply: CommentReportWithDetails | { error: string };
  }>(
    "/",
    {
      preValidation: [fastify.authenticate],
      schema: {
        body: {
          type: "object",
          required: ["reportedCommentId", "reason", "details"],
          properties: {
            reportedCommentId: { type: "string" },
            reason: {
              type: "string",
              enum: Object.values(ReportReason),
            },
            details: { type: "string", minLength: 10, maxLength: 1000 },
          },
        },
      },
    },
    async (request, reply) => {
      try {
        const report = await commentReportService.createReport(
          request.user.id,
          request.body,
        );
        return reply.status(201).send(report);
      } catch (error) {
        if (
          error instanceof Error &&
          (error.message.includes("already have a pending report") ||
            error.message.includes("maximum number of pending reports"))
        ) {
          return reply.status(409).send({ error: error.message });
        }
        throw error;
      }
    },
  );

  // Get all comment reports (admin only)
  fastify.get<{
    Querystring: { status?: ReportStatus };
    Reply: CommentReportWithDetails[];
  }>(
    "/",
    {
      preValidation: [fastify.authenticate, adminGuard],
      schema: {
        querystring: {
          type: "object",
          properties: {
            status: { type: "string" },
          },
        },
      },
    },
    async (request, reply) => {
      const reports = await commentReportService.getAllReports(
        request.query.status,
      );
      return reply.send(reports);
    },
  );

  // Get a single comment report by ID (admin only)
  fastify.get<{
    Params: { id: string };
    Reply: CommentReportWithDetails | { error: string };
  }>(
    "/:id",
    {
      preValidation: [fastify.authenticate, adminGuard],
    },
    async (request, reply) => {
      const report = await commentReportService.getReportById(request.params.id);

      if (!report) {
        return reply.status(404).send({ error: "Report not found" });
      }

      return reply.send(report);
    },
  );

  // Update a comment report (admin only)
  fastify.put<{
    Params: { id: string };
    Body: UpdateCommentReportDto;
    Reply: CommentReportWithDetails;
  }>(
    "/:id",
    {
      preValidation: [fastify.authenticate, adminGuard],
      schema: {
        body: {
          type: "object",
          required: ["status"],
          properties: {
            status: { type: "string" },
            reviewNotes: { type: "string", maxLength: 1000 },
          },
        },
      },
    },
    async (request, reply) => {
      const report = await commentReportService.updateReport(
        request.params.id,
        request.user.id,
        request.body,
      );

      // Check for report achievements for the original reporter
      if (report.status === "ACTION_TAKEN" || report.status === "DISMISSED") {
        const achievementService = new AchievementService();
        await achievementService.checkAchievements(
          report.reporterId,
          AchievementCategory.Report,
          request
        );
      }

      return reply.send(report);
    },
  );
};

export default commentReportsRoutes;
