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

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

const reportsRoutes: FastifyPluginAsync = async (fastify) => {
  const reportService = new ReportService();

  // Create a new report (authenticated users)
  fastify.post<{
    Body: CreateReportDto;
    Reply: ProfileReportWithUsers | { error: string };
  }>(
    "/",
    {
      preValidation: [fastify.authenticate],
      schema: {
        body: {
          type: "object",
          required: ["reportedUserId", "reason", "details"],
          properties: {
            reportedUserId: { type: "string" },
            reason: {
              type: "string",
              enum: Object.values(ReportReason),
            },
            details: { type: "string", minLength: 10, maxLength: 1000 },
          },
        },
      },
    },
    async (request, reply) => {
      try {
        const report = await reportService.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")
        ) {
          return reply.status(409).send({ error: error.message });
        }
        throw error;
      }
    },
  );

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

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

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

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

  // Update a report (admin only)
  fastify.put<{
    Params: { id: string };
    Body: UpdateReportDto;
    Reply: ProfileReportWithUsers;
  }>(
    "/: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 reportService.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 reportsRoutes;
