import { NextResponse } from 'next/server';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { sanitizeCsvCell } from '@/lib/csv/sanitize-csv-cell';
import { errorResponse } from '@/lib/errors';
import { searchAuditLogs } from '@/lib/services/audit-search.service';

/**
 * M-AU03 - CSV export of audit log search results.
 *
 * Accepts the same query-string filters as `GET /api/v1/admin/audit`
 * (q, userId, action, entityType, entityId, severity, source, from, to)
 * and streams up to 10 000 rows back as a CSV download. The 10k cap
 * keeps the response under a couple of megabytes; reps wanting deeper
 * history should narrow the filter or run multiple exports.
 *
 * Permission gate matches the read endpoint: `admin.view_audit_log`.
 */
export const GET = withAuth(
  withPermission('admin', 'view_audit_log', async (req, ctx) => {
    try {
      const url = new URL(req.url);
      const params = url.searchParams;
      const parseDate = (v: string | null): Date | undefined => {
        if (!v) return undefined;
        const d = new Date(v);
        return Number.isFinite(d.getTime()) ? d : undefined;
      };

      // Cap the export at 10 000 rows. Anyone needing deeper history
      // can scroll through the paginated UI or narrow the date range.
      const HARD_CAP = 10_000;

      let collected: Awaited<ReturnType<typeof searchAuditLogs>>['rows'] = [];
      let cursor: { createdAt: Date; id: string } | undefined;
      // Run a small loop so we paginate through the cursor-based search
      // service to fill up to HARD_CAP rows.
      while (collected.length < HARD_CAP) {
        const remaining = HARD_CAP - collected.length;
        const page = await searchAuditLogs({
          portId: ctx.portId,
          q: params.get('q') ?? undefined,
          userId: params.get('userId') ?? undefined,
          action: params.get('action') ?? undefined,
          entityType: params.get('entityType') ?? undefined,
          entityId: params.get('entityId') ?? undefined,
          severity: params.get('severity') ?? undefined,
          source: params.get('source') ?? undefined,
          from: parseDate(params.get('from')),
          to: parseDate(params.get('to')),
          limit: Math.min(remaining, 500),
          cursor,
        });
        collected = collected.concat(page.rows);
        if (!page.nextCursor) break;
        cursor = page.nextCursor;
      }

      const csv = buildCsv(collected);
      const filename = `audit-log-${new Date().toISOString().slice(0, 10)}.csv`;
      return new NextResponse(csv, {
        headers: {
          'Content-Type': 'text/csv; charset=utf-8',
          'Content-Disposition': `attachment; filename="${filename}"`,
        },
      });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);

/**
 * RFC 4180 CSV serializer. Escapes embedded quotes by doubling them and
 * wraps any field containing comma / quote / newline in double-quotes.
 * Trailing CRLF terminator per spec.
 */
function buildCsv(rows: Awaited<ReturnType<typeof searchAuditLogs>>['rows']): string {
  const headers = [
    'createdAt',
    'id',
    'portId',
    'userId',
    'action',
    'entityType',
    'entityId',
    'severity',
    'source',
    'ipAddress',
    'userAgent',
    'metadata',
    'oldValue',
    'newValue',
  ];

  const escape = (v: unknown): string => {
    if (v === null || v === undefined) return '';
    const raw = typeof v === 'object' ? JSON.stringify(v) : String(v);
    // Neutralize spreadsheet formula triggers before RFC 4180 framing —
    // the leading quote is part of the cell value, not the CSV escaping.
    const s = sanitizeCsvCell(raw);
    if (/[",\n\r]/.test(s)) {
      return `"${s.replace(/"/g, '""')}"`;
    }
    return s;
  };

  const lines = [headers.join(',')];
  for (const r of rows) {
    lines.push(
      [
        r.createdAt instanceof Date ? r.createdAt.toISOString() : r.createdAt,
        r.id,
        r.portId,
        r.userId,
        r.action,
        r.entityType,
        r.entityId,
        r.severity,
        r.source,
        r.ipAddress,
        r.userAgent,
        r.metadata,
        r.oldValue,
        r.newValue,
      ]
        .map(escape)
        .join(','),
    );
  }
  return lines.join('\r\n') + '\r\n';
}
