import { NextResponse } from 'next/server';
import { and, desc, eq, isNotNull, isNull, sql, type SQL } from 'drizzle-orm';
import { z } from 'zod';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { parseQuery } from '@/lib/api/route-helpers';
import { db } from '@/lib/db';
import { documentSends } from '@/lib/db/schema/brochures';
import { errorResponse } from '@/lib/errors';

const querySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).default(50),
  status: z.enum(['all', 'sent', 'failed']).default('all'),
  kind: z.enum(['berth_pdf', 'brochure']).optional(),
  cursorAt: z.string().optional(),
  cursorId: z.string().optional(),
});

export const GET = withAuth(
  withPermission('admin', 'view_audit_log', async (req, ctx) => {
    try {
      const query = parseQuery(req, querySchema);
      const conds: SQL[] = [eq(documentSends.portId, ctx.portId)];
      if (query.kind) conds.push(eq(documentSends.documentKind, query.kind));
      if (query.status === 'failed') conds.push(isNotNull(documentSends.failedAt));
      if (query.status === 'sent') conds.push(isNull(documentSends.failedAt));
      if (query.cursorAt && query.cursorId) {
        const cursorAt = new Date(query.cursorAt).toISOString();
        conds.push(
          sql`(${documentSends.sentAt}, ${documentSends.id}) < (${cursorAt}::timestamptz, ${query.cursorId})`,
        );
      }

      const rows = await db
        .select()
        .from(documentSends)
        .where(and(...conds))
        .orderBy(desc(documentSends.sentAt), desc(documentSends.id))
        .limit(query.limit + 1);

      const hasMore = rows.length > query.limit;
      const page = hasMore ? rows.slice(0, query.limit) : rows;
      const last = page[page.length - 1];
      const nextCursor =
        hasMore && last ? { sentAt: last.sentAt.toISOString(), id: last.id } : null;

      // Counts for the filter chips
      const sentCountRows = await db
        .select({ count: sql<number>`count(*)::int` })
        .from(documentSends)
        .where(and(eq(documentSends.portId, ctx.portId), isNull(documentSends.failedAt)));
      const failedCountRows = await db
        .select({ count: sql<number>`count(*)::int` })
        .from(documentSends)
        .where(and(eq(documentSends.portId, ctx.portId), isNotNull(documentSends.failedAt)));

      const counts = {
        sent: sentCountRows[0]?.count ?? 0,
        failed: failedCountRows[0]?.count ?? 0,
        all: (sentCountRows[0]?.count ?? 0) + (failedCountRows[0]?.count ?? 0),
      };

      return NextResponse.json({ data: page, pagination: { nextCursor }, counts });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);
