import { FastifyInstance } from "fastify";
import { z } from "zod";
import prisma from "../../config/database";
import { requirePermission } from "../../middleware/auth";
import { logAudit } from "../../services/audit";
import { success, paginated, error } from "../../utils/response";
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
import { parseBody } from "../../schemas/common";

// DELETE_ALL_CONFIRM must be sent literally in the body to authorize a
// full audit-log wipe. Protects against accidental / automated wipes of
// forensic history.
const DELETE_ALL_CONFIRM = "DELETE_ALL_AUDIT" as const;

const AuditCleanupSchema = z.strictObject({
  days: z.number().int().nonnegative().optional(),
  confirm: z.string().optional(),
});

export default async function auditLogRoutes(
  fastify: FastifyInstance,
): Promise<void> {
  fastify.get(
    "/",
    { preHandler: requirePermission("settings.audit") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const { page, limit, skip, order, search } = parsePagination(query);

      const where: Record<string, unknown> = {};
      if (query.action) where.action = String(query.action);
      if (query.entity_type) where.entity_type = String(query.entity_type);
      if (query.user_id) {
        const userId = Number(query.user_id);
        if (!Number.isInteger(userId) || userId <= 0) {
          return error(reply, "Neplatné ID uživatele", 400);
        }
        where.user_id = userId;
      }
      if (search) where.description = { contains: search };

      if (query.date_from || query.date_to) {
        const dateFilter: Record<string, Date> = {};
        if (query.date_from) {
          const from = new Date(String(query.date_from));
          if (isNaN(from.getTime())) {
            return error(reply, "Neplatné datum od", 400);
          }
          dateFilter.gte = from;
        }
        if (query.date_to) {
          const to = new Date(String(query.date_to) + "T23:59:59");
          if (isNaN(to.getTime())) {
            return error(reply, "Neplatné datum do", 400);
          }
          dateFilter.lte = to;
        }
        where.created_at = dateFilter;
      }

      const [logs, total] = await Promise.all([
        prisma.audit_logs.findMany({
          where,
          skip,
          take: limit,
          orderBy: { created_at: order },
        }),
        prisma.audit_logs.count({ where }),
      ]);

      return paginated(reply, logs, buildPaginationMeta(total, page, limit));
    },
  );

  // POST /api/admin/audit-log/cleanup — delete old audit logs
  // days=0 with confirm="DELETE_ALL_AUDIT" wipes everything (intentionally
  // a two-step path so a stray API call cannot destroy forensic history).
  fastify.post(
    "/cleanup",
    { preHandler: requirePermission("settings.audit") },
    async (request, reply) => {
      const parsed = parseBody(AuditCleanupSchema, request.body);
      if ("error" in parsed) {
        return error(reply, parsed.error, 400);
      }
      const { days, confirm } = parsed.data;

      // Wipe-all path: requires explicit confirmation literal.
      if (days === 0) {
        if (confirm !== DELETE_ALL_CONFIRM) {
          return error(
            reply,
            `Pro smazání všech audit logů je nutné odeslat confirm: "${DELETE_ALL_CONFIRM}"`,
            400,
          );
        }
        const result = await prisma.audit_logs.deleteMany({});
        await logAudit({
          request,
          authData: request.authData,
          action: "delete",
          entityType: "audit_logs",
          description: `Uživatel ${request.authData?.username ?? "unknown"} smazal všechny audit logy, počet: ${result.count}`,
        });
        return success(reply, null, 200, `Smazáno ${result.count} záznamů`);
      }

      if (days !== undefined && days > 0) {
        const cutoff = new Date();
        cutoff.setDate(cutoff.getDate() - days);
        const result = await prisma.audit_logs.deleteMany({
          where: { created_at: { lt: cutoff } },
        });
        await logAudit({
          request,
          authData: request.authData,
          action: "delete",
          entityType: "audit_logs",
          description: `Uživatel ${request.authData?.username ?? "unknown"} smazal audit logy starší než ${days} dní, počet: ${result.count}`,
        });
        return success(
          reply,
          null,
          200,
          `Smazáno ${result.count} záznamů starších než ${days} dní`,
        );
      }

      return error(reply, "Zadejte počet dní", 400);
    },
  );
}
