import { NextResponse } from "next/server";
import { Prisma } from "@prisma/client";
import * as XLSX from "xlsx";

import { requireApiAccess } from "@/lib/authorization";
import { prisma } from "@/lib/prisma";

function parseDateStart(value: string | null) {
  if (!value) return null;
  const date = new Date(`${value}T00:00:00.000Z`);
  return Number.isNaN(date.getTime()) ? null : date;
}

function parseDateEnd(value: string | null) {
  if (!value) return null;
  const date = new Date(`${value}T23:59:59.999Z`);
  return Number.isNaN(date.getTime()) ? null : date;
}

function buildWhere(searchParams: URLSearchParams): Prisma.AuditTrailWhereInput {
  const action = searchParams.get("action")?.trim();
  const userId = searchParams.get("user_id")?.trim();
  const dateFrom = parseDateStart(searchParams.get("date_from"));
  const dateTo = parseDateEnd(searchParams.get("date_to"));
  const search = searchParams.get("search")?.trim();

  const where: Prisma.AuditTrailWhereInput = {};

  if (action) {
    where.action = action;
  }

  if (userId) {
    try {
      where.userId = BigInt(userId);
    } catch {
      where.userId = BigInt(-1);
    }
  }

  if (dateFrom || dateTo) {
    where.occurredAt = {
      ...(dateFrom ? { gte: dateFrom } : {}),
      ...(dateTo ? { lte: dateTo } : {})
    };
  }

  if (search) {
    where.OR = [
      { action: { contains: search, mode: "insensitive" } },
      { entityType: { contains: search, mode: "insensitive" } },
      { entityId: { contains: search, mode: "insensitive" } },
      { pathname: { contains: search, mode: "insensitive" } },
      { summary: { contains: search, mode: "insensitive" } },
      { user: { name: { contains: search, mode: "insensitive" } } },
      { user: { email: { contains: search, mode: "insensitive" } } },
      { user: { username: { contains: search, mode: "insensitive" } } }
    ];
  }

  return where;
}

export async function GET(request: Request) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const { searchParams } = new URL(request.url);
  const where = buildWhere(searchParams);

  const items = await prisma.auditTrail.findMany({
    where,
    include: {
      user: {
        include: {
          role: { select: { code: true } }
        }
      }
    },
    orderBy: [{ occurredAt: "desc" }, { id: "desc" }]
  });

  const rows = items.map((item) => ({
    "Occurred At": item.occurredAt.toISOString(),
    Action: item.action,
    "Entity Type": item.entityType,
    "Entity ID": item.entityId ?? "",
    Method: item.method,
    Pathname: item.pathname,
    "Status Code": item.statusCode,
    Summary: item.summary ?? "",
    User: item.user?.name ?? "",
    Email: item.user?.email ?? "",
    Username: item.user?.username ?? "",
    Role: item.user?.role.code ?? "",
    Metadata: item.metadata ? JSON.stringify(item.metadata) : ""
  }));

  const workbook = XLSX.utils.book_new();
  const worksheet = XLSX.utils.json_to_sheet(rows);
  XLSX.utils.book_append_sheet(workbook, worksheet, "Audit Trail");
  const buffer = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" });

  return new NextResponse(buffer, {
    status: 200,
    headers: {
      "Content-Type":
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      "Content-Disposition": `attachment; filename=\"audit-trail-${new Date()
        .toISOString()
        .slice(0, 10)}.xlsx\"`
    }
  });
}
