import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createAdminClient } from '@/lib/supabase/admin'
import { requireParticipant } from '@/lib/api-guard'
import { publicOrigin } from '@/lib/app-url'
import { createPermitRequest } from '@/lib/data/permit-requests'
import { PERMIT_PAYMENT_GATE, PERMIT_PAYMENT_GATE_ERROR } from '@/lib/domain/permit-payment'
import type { Permit, Trip } from '@/types/db'

const schema = z.object({
  type: z.enum(['permit_request', 'route_request']),
  state_code: z.string().trim().max(2).optional().or(z.literal('')),
  notes: z.string().trim().max(2000).optional().or(z.literal('')),
  // route requests: express/extended is normally assigned by the backend;
  // the client passes it when known (demo) so the price shown matches.
  route_type: z.enum(['express', 'extended']).optional(),
  // Task 14: which OTHER participants the requester chose to inform
  // (participant ids). Actual emails are sent by the backend later.
  notify: z.array(z.string().uuid()).max(20).optional(),
  // Task 69: how a route was paid — a prepaid Express Route credit, or the
  // cart ("card"). Drives the real, decrementing credit balance.
  paid_with: z.enum(['credit', 'card']).optional(),
  // Task 75: re-ordering an expired permit. `payer` is only a choice for a
  // broker; everyone else is liable themselves.
  payer: z.enum(['requester', 'broker', 'carrier']).optional(),
  replaces_permit_id: z.string().uuid().optional(),
  // 2026-09-29 (D4): proof that the customer confirmed a card on Synchron's
  // secure page. Required for permit requests when PERMIT_PAYMENT_GATE is on;
  // the two-step dialog's `complete` route supplies it.
  payment_confirmation_token: z.string().trim().min(1).max(200).optional(),
})

/**
 * Manual permit/route request — no payments in the MVP. Any trip participant
 * can request ("anyone that has access to this load can buy the Google Maps").
 * Recorded in Supabase and forwarded to Synchron via the existing integration.
 *
 * The person making the request is the CLIENT on the Synchron order (Task 75):
 * "the person that's making that request should be the one that's set as the
 * client for that order when it's being sent to Synchron."
 */
export async function POST(req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
  const { id: tripId } = await ctx.params
  const guard = await requireParticipant(tripId)
  if (!guard.ok) return guard.response
  const { user, participant } = guard

  const parsed = schema.safeParse(await req.json().catch(() => ({})))
  if (!parsed.success) return NextResponse.json({ error: 'Invalid request.' }, { status: 400 })
  const input = parsed.data

  // Only a broker may put the bill on someone else (Nash: "if it's a broker
  // does it, the broker has the power to choose who is going to pay").
  const payer: 'requester' | 'broker' | 'carrier' | null =
    input.type === 'permit_request'
      ? participant.role === 'broker' && input.payer
        ? input.payer
        : 'requester'
      : null

  const admin = createAdminClient()
  const label = participant.name || user.email || 'participant'
  const { data: tripRow } = await admin.from('trips').select('*').eq('id', tripId).single()
  const trip = tripRow as Trip | null
  if (!trip) return NextResponse.json({ error: 'Trip not found.' }, { status: 404 })
  if (input.type === 'permit_request') {
    const { data: rateCon } = await admin.from('documents').select('id').eq('trip_id', tripId).eq('kind', 'rate_confirmation').limit(1)
    if (!rateCon?.length) return NextResponse.json({ error: 'Add the rate confirmation before requesting a permit.' }, { status: 400 })
  }

  // A re-order must point at a permit on THIS trip.
  let replacedPermit: Permit | null = null
  if (input.replaces_permit_id) {
    const { data } = await admin
      .from('permits')
      .select('*')
      .eq('id', input.replaces_permit_id)
      .eq('trip_id', tripId)
      .maybeSingle()
    if (!data) return NextResponse.json({ error: 'That permit is not on this trip.' }, { status: 400 })
    replacedPermit = data as Permit
  }

  const stateCode = input.state_code?.toUpperCase() || replacedPermit?.state_code || null
  if (input.type === 'permit_request' && !/^[A-Z]{2}$/.test(stateCode || '')) {
    return NextResponse.json({ error: 'Choose a permit state.' }, { status: 400 })
  }

  // D4 gate: a permit order is released only after the card-on-file step.
  if (PERMIT_PAYMENT_GATE && input.type === 'permit_request' && !input.payment_confirmation_token) {
    return NextResponse.json({ error: PERMIT_PAYMENT_GATE_ERROR, readiness: 'card_required' }, { status: 409 })
  }

  const created = await createPermitRequest({
    tripId,
    trip,
    user: { id: user.id, email: user.email, name: user.name },
    participant,
    label,
    type: input.type,
    stateCode,
    notes: input.notes || null,
    routeType: input.route_type ?? null,
    notify: input.notify ?? null,
    paidWith: input.type === 'route_request' ? (input.paid_with ?? null) : null,
    payer,
    replacedPermit,
    origin: publicOrigin(req),
  })
  if (!created.ok) return NextResponse.json({ error: created.error }, { status: 500 })

  return NextResponse.json({ ok: true, request: created.request, ...(created.email ? { email: created.email } : {}) })
}
