import { NextResponse } from "next/server";
import { z } from "zod";
import {
  isValidIndianMobile,
  normalizeAadhaar,
  normalizeMobile,
} from "@/lib/aadhaar";
import { readSessionToken } from "@/lib/otp";
import { createVisitor } from "@/lib/visitors";
import { auditLog } from "@/lib/audit";
import { EVENT } from "@/lib/event";
import { evaluateHuman, humanRejectResponse } from "@/lib/human";
import { requestMeta } from "@/lib/request-meta";
import {
  recordHumanCheckReject,
  withRegistrationSecurity,
} from "@/lib/security";
import { safeError } from "@/lib/safe-log";

const schema = z.object({
  aadhaar_number: z.string().min(12),
  name: z.string().min(2).max(120),
  age: z.number().int().min(1).max(120),
  gender: z.string().min(1),
  mobile: z.string().min(10),
  emergency_contact: z.string().min(10),
  address_line1: z.string().min(3).max(200),
  address_line2: z.string().max(200).optional().nullable(),
  state: z.string().min(2),
  city: z.string().max(120).optional().nullable(),
  district: z.string().max(120).optional().nullable(),
  pincode: z.string().max(10).optional().nullable(),
  post_office: z.string().max(160).optional().nullable(),
  arrival_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
  transport_mode: z.enum(["Train", "Flight", "Bus", "Personal Vehicle"]),
  stay_type: z.enum(["Hotel", "Tent City", "Akhada", "Day Visit"]),
  channel: z.string().default("website"),
  human: z.unknown().optional(),
});

export async function POST(req: Request) {
  return withRegistrationSecurity(
    req,
    {
      routeGroup: "registration",
      pathNorm: "/api/v1/registration/visitors",
    },
    async () => {
      const meta = requestMeta(req);
      try {
        const auth = req.headers.get("authorization") || "";
        const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
        if (!token) {
          await auditLog({
            step: "create_visitor",
            outcome: "unauthorized",
            ip: meta.ip,
            userAgent: meta.userAgent,
          });
          return NextResponse.json(
            { ok: false, error: "Session expired. Please verify OTP again." },
            { status: 401 },
          );
        }

        let session;
        try {
          session = await readSessionToken(token);
        } catch {
          await auditLog({
            step: "create_visitor",
            outcome: "session_expired",
            ip: meta.ip,
            userAgent: meta.userAgent,
          });
          return NextResponse.json(
            { ok: false, error: "Session expired. Please verify OTP again." },
            { status: 401 },
          );
        }

        const body = await req.json();
        const human = evaluateHuman(body.human);
        if (!human.ok) {
          await auditLog({
            step: "human_check",
            outcome: "reject",
            ip: meta.ip,
            userAgent: meta.userAgent,
            meta: {
              reason: human.reason,
              score: human.score,
              at: "create_visitor",
            },
          });
          recordHumanCheckReject({
            at: "create_visitor",
            reason: human.reason,
            score: human.score,
            sourceIp: meta.ip,
          });
          return NextResponse.json(humanRejectResponse(human.reason), {
            status: 403,
          });
        }

        const parsed = schema.safeParse(body);
        if (!parsed.success) {
          await auditLog({
            step: "create_visitor",
            outcome: "invalid_fields",
            ip: meta.ip,
            userAgent: meta.userAgent,
          });
          return NextResponse.json(
            { ok: false, error: "Please complete all mandatory fields." },
            { status: 400 },
          );
        }

        const data = parsed.data;
        const mobile = normalizeMobile(data.mobile);
        const emergency = normalizeMobile(data.emergency_contact);

        if (!isValidIndianMobile(mobile) || !isValidIndianMobile(emergency)) {
          return NextResponse.json(
            {
              ok: false,
              error: "Mobile numbers must be valid 10-digit Indian numbers.",
            },
            { status: 400 },
          );
        }
        if (mobile === emergency) {
          return NextResponse.json(
            {
              ok: false,
              error:
                "Emergency contact cannot match your primary mobile number.",
            },
            { status: 400 },
          );
        }

        const arrival = new Date(data.arrival_date + "T00:00:00");
        const eventStart = new Date(EVENT.startDate + "T00:00:00");
        const eventEnd = new Date(EVENT.endDate + "T00:00:00");
        if (arrival < eventStart || arrival > eventEnd) {
          return NextResponse.json(
            {
              ok: false,
              error: `Arrival date must be during Simhastha Mahakumbh (${EVENT.dateRangeEn}).`,
            },
            { status: 400 },
          );
        }

        if (mobile !== session.mobile) {
          await auditLog({
            step: "create_visitor",
            outcome: "mobile_mismatch",
            ip: meta.ip,
            userAgent: meta.userAgent,
          });
          return NextResponse.json(
            {
              ok: false,
              error: "Mobile number must match the OTP-verified number.",
            },
            { status: 400 },
          );
        }

        const result = await createVisitor({
          aadhaar: normalizeAadhaar(data.aadhaar_number),
          aadhaarHash: session.aadhaar_hash,
          name: data.name,
          age: data.age,
          gender: data.gender,
          mobile,
          emergencyContact: emergency,
          addressLine1: data.address_line1,
          addressLine2: data.address_line2 || null,
          state: data.state,
          city: data.city || null,
          district: data.district || null,
          pincode: data.pincode || null,
          postOffice: data.post_office || null,
          arrivalDate: data.arrival_date,
          transportMode: data.transport_mode,
          stayType: data.stay_type,
          channel: data.channel || "website",
          registrationIp: meta.ip,
        });

        if (!result.ok) {
          await auditLog({
            step: "create_visitor",
            outcome: "duplicate",
            ip: meta.ip,
            userAgent: meta.userAgent,
            meta: { pass_no: result.existingPass },
          });
          return NextResponse.json(
            {
              ok: false,
              error: result.error,
              pass_no: result.existingPass,
            },
            { status: 409 },
          );
        }

        await auditLog({
          step: "create_visitor",
          outcome: "ok",
          ip: meta.ip,
          userAgent: meta.userAgent,
          meta: { pass_no: result.pass_no, human_score: human.score },
        });

        return NextResponse.json(result);
      } catch (e) {
        safeError(e);
        return NextResponse.json(
          { ok: false, error: "Registration failed. Please try again." },
          { status: 500 },
        );
      }
    },
  );
}
