import { NextResponse } from 'next/server';
import { and, desc, eq, inArray, 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 { websiteSubmissions } from '@/lib/db/schema/website-submissions';
import { errorResponse } from '@/lib/errors';

const querySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).default(50),
  kind: z.enum(['berth_inquiry', 'residence_inquiry', 'contact_form']).optional(),
  /** Default 'inbox' (open + assigned) so resolved/dismissed roll off
   *  the active queue. Pass 'all' to surface every row including
   *  history. */
  state: z.enum(['inbox', 'open', 'assigned', 'converted', 'dismissed', 'all']).default('inbox'),
  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(websiteSubmissions.portId, ctx.portId)];
      if (query.kind) conds.push(eq(websiteSubmissions.kind, query.kind));
      if (query.state === 'inbox') {
        conds.push(inArray(websiteSubmissions.triageState, ['open', 'assigned']));
      } else if (query.state !== 'all') {
        conds.push(eq(websiteSubmissions.triageState, query.state));
      }
      if (query.cursorAt && query.cursorId) {
        const cursorAt = new Date(query.cursorAt).toISOString();
        conds.push(
          sql`(${websiteSubmissions.receivedAt}, ${websiteSubmissions.id}) < (${cursorAt}::timestamptz, ${query.cursorId})`,
        );
      }

      const rows = await db
        .select()
        .from(websiteSubmissions)
        .where(and(...conds))
        .orderBy(desc(websiteSubmissions.receivedAt), desc(websiteSubmissions.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 ? { receivedAt: last.receivedAt.toISOString(), id: last.id } : null;

      // Lightweight count by kind for the page header
      const countsRows = await db
        .select({ kind: websiteSubmissions.kind, count: sql<number>`count(*)::int` })
        .from(websiteSubmissions)
        .where(eq(websiteSubmissions.portId, ctx.portId))
        .groupBy(websiteSubmissions.kind);
      const counts = Object.fromEntries(countsRows.map((r) => [r.kind, r.count])) as Record<
        string,
        number
      >;

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