import { NextResponse, type NextRequest } from 'next/server';
import { and, eq, sql } from 'drizzle-orm';

import { db } from '@/lib/db';
import { documentSendOpens, documentSends } from '@/lib/db/schema/brochures';
import { logger } from '@/lib/logger';
import { trackEvent } from '@/lib/services/umami.service';

/**
 * GET /api/public/email-pixel/[sendId]
 *
 * Returns a 1×1 transparent GIF and records an open event in
 * `document_send_opens` + bumps the cached aggregates on `document_sends`.
 *
 * Lookups are gated by `track_opens=true` on the send row, so a leaked
 * sendId for an untracked email is a no-op (the pixel still returns
 * 200/GIF so email clients don't surface a broken-image icon).
 *
 * Privacy: we deliberately don't store IP addresses or any data beyond
 * user-agent + referer. Apple Mail privacy proxy pre-fetches images, so
 * opens from iOS users are over-counted; image-blocking clients
 * (Outlook with images disabled) under-count. Standard email-tracking
 * caveats apply.
 */

// 1×1 transparent GIF, base64-encoded. Generated once at module-load so
// every request returns the same buffer without re-allocating.
const TRANSPARENT_GIF = Buffer.from(
  'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
  'base64',
);

function gifResponse(): NextResponse {
  return new NextResponse(TRANSPARENT_GIF as unknown as BodyInit, {
    status: 200,
    headers: {
      'Content-Type': 'image/gif',
      'Content-Length': String(TRANSPARENT_GIF.length),
      // Tell every upstream cache to keep its hands off - we count opens
      // on the FETCH itself, so any cached response is a missed open.
      'Cache-Control': 'no-store, no-cache, must-revalidate, private',
      Pragma: 'no-cache',
      Expires: '0',
    },
  });
}

export async function GET(
  req: NextRequest,
  ctx: { params: Promise<{ sendId: string }> },
): Promise<NextResponse> {
  const { sendId } = await ctx.params;

  try {
    // Look up the send row; ignore unknown / un-tracked sends silently.
    const sendRow = await db.query.documentSends.findFirst({
      where: and(eq(documentSends.id, sendId), eq(documentSends.trackOpens, true)),
      columns: { id: true, portId: true, recipientEmail: true, documentKind: true },
    });
    if (!sendRow) return gifResponse();

    const userAgent = req.headers.get('user-agent');
    const referer = req.headers.get('referer');

    // Best-effort write - never block the pixel response on a slow DB.
    // The pixel must return promptly so email clients render normally.
    db.insert(documentSendOpens)
      .values({
        portId: sendRow.portId,
        sendId: sendRow.id,
        userAgent: userAgent ?? null,
        referer: referer ?? null,
      })
      .then(() =>
        db
          .update(documentSends)
          .set({
            openCount: sql`${documentSends.openCount} + 1`,
            firstOpenedAt: sql`COALESCE(${documentSends.firstOpenedAt}, NOW())`,
          })
          .where(eq(documentSends.id, sendRow.id)),
      )
      .catch((err) => {
        logger.warn({ err, sendId: sendRow.id }, 'email-pixel: failed to record open');
      });

    // Cross-post to Umami so the marketing funnel includes opens. Don't
    // await - fire-and-forget so the pixel response stays fast.
    trackEvent(
      sendRow.portId,
      'email-opened',
      {
        sendId: sendRow.id,
        documentKind: sendRow.documentKind,
      },
      'email://pixel',
    ).catch((err) => {
      logger.debug({ err, sendId: sendRow.id }, 'email-pixel: umami cross-post failed');
    });

    return gifResponse();
  } catch (err) {
    logger.warn({ err, sendId }, 'email-pixel: unexpected error');
    return gifResponse();
  }
}
