import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createAdminClient } from '@/lib/supabase/admin'
import { publicOrigin } from '@/lib/app-url'
import { requireParticipant } from '@/lib/api-guard'
import { canInvite } from '@/lib/domain/permissions'
import { logTripEvent } from '@/lib/audit'
import { describePilotAccess } from '@/lib/domain/pilot'

// Nash (2026-09-04): "the phone number should be required" (it disambiguates
// existing users); the extension is optional free text. Both accept formatted
// input — never numbers-only strict.
const schema = z.object({
  email: z.string().email(),
  name: z.string().trim().min(1),
  phone: z.string().trim().min(5).max(40),
  phone_ext: z.string().trim().max(20).optional().or(z.literal('')),
  role: z.enum(['broker', 'dispatcher', 'driver', 'pilot', 'shipper']),
  // Pilot access chosen at invite time (Nash, 2026-09-12). Phase 1 records
  // the choice in the trip history; per-scope enforcement is the pilot
  // backend phase (PILOT-MANAGEMENT-TASKS, Module F).
  pilot_access: z
    .discriminatedUnion('type', [
      z.object({ type: z.literal('full_trip') }),
      z.object({ type: z.literal('states'), states: z.array(z.string().trim().min(2).max(2)).max(60) }),
      z.object({
        type: z.literal('permits'),
        permit_ids: z.array(z.string().uuid()).max(200),
        labels: z.array(z.string().max(80)).max(200).optional(),
      }),
      z.object({ type: z.literal('decide_later') }),
    ])
    .optional(),
})

/** Invite a person to a trip with a per-trip role. */
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 invitation details.' }, { status: 400 })
  }
  const input = parsed.data

  if (!canInvite(participant.role, input.role)) {
    return NextResponse.json(
      { error: `As ${participant.role} you cannot invite a ${input.role}.` },
      { status: 403 },
    )
  }

  const admin = createAdminClient()

  const participantRow = {
    trip_id: tripId,
    email: input.email,
    name: input.name,
    phone: input.phone,
    role: input.role,
    status: 'invited',
    invited_by: user.id,
  }
  // TODO(backend): on invite-accept, cross-reference email + phone +
  // extension to pinpoint the exact existing user (same company email can
  // be shared by several dispatchers — the extension disambiguates).
  let { data: newParticipant, error: pErr } = await admin
    .from('trip_participants')
    .insert({ ...participantRow, phone_ext: input.phone_ext || null })
    .select()
    .single()
  if (pErr?.message.includes('phone_ext')) {
    // Graceful until migration 0007 adds the column.
    const retry = await admin.from('trip_participants').insert(participantRow).select().single()
    newParticipant = retry.data
    pErr = retry.error
  }
  if (pErr) {
    const msg = pErr.message.includes('duplicate')
      ? 'That person is already on this trip with that role.'
      : 'Could not create the invitation.'
    return NextResponse.json({ error: msg }, { status: 400 })
  }

  const { data: invitation } = await admin
    .from('trip_invitations')
    .insert({
      trip_id: tripId,
      participant_id: newParticipant.id,
      email: input.email,
      role: input.role,
      invited_by: user.id,
    })
    .select()
    .single()

  await logTripEvent({
    tripId,
    actorId: user.id,
    actorLabel: participant.name || user.email || 'participant',
    action: 'participant_invited',
    detail: {
      email: input.email,
      role: input.role,
      ...(input.role === 'pilot' ? { pilot_access: describePilotAccess(input.pilot_access) } : {}),
    },
  })

  const origin = publicOrigin(req)
  return NextResponse.json({
    ok: true,
    invite_url: invitation ? `${origin}/invite/${invitation.token}` : null,
  })
}
