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

import { db } from '@/lib/db';
import { ports } from '@/lib/db/schema/ports';
import { createAuditLog } from '@/lib/audit';
import { parseBody } from '@/lib/api/route-helpers';
import { errorResponse, RateLimitError, ValidationError } from '@/lib/errors';
import { checkRateLimit, rateLimiters } from '@/lib/rate-limit';
import { publicInterestSchema } from '@/lib/validators/interests';
import { sendInquiryNotifications } from '@/lib/services/inquiry-notifications.service';
import { createPublicInterest } from '@/lib/services/public-interest.service';

/**
 * Throws RateLimitError if the IP has exceeded the public-form quota.
 * Backed by the Redis sliding-window limiter so the cap survives restarts
 * and is shared across worker processes.
 */
async function gateRateLimit(ip: string): Promise<void> {
  const result = await checkRateLimit(ip, rateLimiters.publicForm);
  if (!result.allowed) {
    const retryAfter = Math.max(1, Math.ceil((result.resetAt - Date.now()) / 1000));
    throw new RateLimitError(retryAfter);
  }
}

// POST /api/public/interests - unauthenticated public interest registration.
// The transactional trio creation (client + yacht + interest, plus optional
// company + membership) lives in `createPublicInterest()` so it's testable
// without an HTTP fixture. This handler is the thin HTTP shell: rate-limit,
// port resolution, body parsing, then post-commit audit log + email fan-out.
export async function POST(req: NextRequest) {
  try {
    const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown';
    await gateRateLimit(ip);

    const data = await parseBody(req, publicInterestSchema);

    // Resolve portId from query param or header (public endpoints need explicit port)
    const portId = req.nextUrl.searchParams.get('portId') ?? req.headers.get('X-Port-Id');
    if (!portId) throw new ValidationError('Port context required');

    const result = await createPublicInterest({ portId, data });

    // ─── Post-commit side-effects (fire-and-forget) ─────────────────────────
    // `AuditLogParams.userId` is `string | null`; null is the documented
    // "system-generated" sentinel and matches `audit_logs.user_id` being
    // nullable in the schema.
    void createAuditLog({
      userId: null,
      portId,
      action: 'create',
      entityType: 'interest',
      entityId: result.interestId,
      newValue: {
        clientId: result.clientId,
        yachtId: result.yachtId,
        companyId: result.companyId,
        source: 'website',
        pipelineStage: 'enquiry',
        berthId: result.berthId,
      },
      metadata: { type: 'public_registration', ip },
      ipAddress: ip,
      userAgent: req.headers.get('user-agent') ?? 'unknown',
    });

    const port = await db.query.ports.findFirst({
      where: eq(ports.id, portId),
      columns: { slug: true },
    });

    void sendInquiryNotifications({
      portId,
      portSlug: port?.slug ?? portId,
      interestId: result.interestId,
      clientFullName: result.fullName,
      clientEmail: data.email,
      clientPhone: data.phone,
      mooringNumber: result.resolvedMooringNumber,
      firstName: result.firstName,
    });

    // L34 carve-out note: this is a public website intake POST (external
    // contract). Unlike the sibling intake routes it already uses the
    // canonical `{ data }` envelope — the external marketing site is
    // coded against THIS shape, so keep `{ data: { id, message } }` and do
    // not "normalize" it toward the bespoke `{ success }`/bare shapes used
    // by the other public intake endpoints.
    return NextResponse.json(
      { data: { id: result.interestId, message: 'Interest registered successfully' } },
      { status: 201 },
    );
  } catch (error) {
    return errorResponse(error);
  }
}
