import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

import { enforcePublicRateLimit } from '@/lib/api/route-helpers';
import { errorResponse, ValidationError } from '@/lib/errors';
import { PORTAL_COOKIE } from '@/lib/portal/auth';
import { signIn } from '@/lib/services/portal-auth.service';

const bodySchema = z.object({
  email: z.string().email(),
  password: z.string().min(1),
});

const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24; // 24h, matches createPortalToken

export async function POST(req: NextRequest): Promise<NextResponse> {
  let body: unknown;
  try {
    body = await req.json();
  } catch {
    return errorResponse(new ValidationError('Email format is invalid'));
  }

  const parsed = bodySchema.safeParse(body);
  if (!parsed.success) {
    return errorResponse(new ValidationError('Email format is invalid'));
  }

  // Per-(ip,email) bucket: 5 attempts / 15min. Keyed on email-lowercase so
  // the limiter is per-account-per-IP, not just per-IP - a NATed network
  // shouldn't be able to lock a single victim by burning their bucket.
  const limited = await enforcePublicRateLimit(
    req,
    'portalSignIn',
    parsed.data.email.toLowerCase(),
  );
  if (limited) return limited;

  try {
    const result = await signIn(parsed.data);
    const res = NextResponse.json({ success: true });
    res.cookies.set(PORTAL_COOKIE, result.token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'lax',
      path: '/',
      maxAge: SESSION_MAX_AGE_SECONDS,
    });
    return res;
  } catch (err) {
    return errorResponse(err);
  }
}
