import { NextRequest, NextResponse } from 'next/server'
import { createAdminClient } from '@/lib/supabase/admin'
import { getSessionUser } from '@/lib/auth'
import { logTripEvent } from '@/lib/audit'
import { invitationAcceptState } from '@/lib/domain/invitations'
import { assignTripCarrier, carrierCompaniesForUsers } from '@/lib/data/carrier-assignment'
import { resolveCarrier } from '@/lib/domain/carrier-assignment'
import { evaluateParticipantRules } from '@/lib/data/auto-participants'
import type { TripParticipant } from '@/types/db'

/** Accept a trip invitation: link the participant row to the signed-in user. */
export async function POST(req: NextRequest) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })

  const { token } = (await req.json().catch(() => ({}))) as { token?: string }
  if (!token) return NextResponse.json({ error: 'Missing token.' }, { status: 400 })

  const admin = createAdminClient()
  const { data: invitation } = await admin
    .from('trip_invitations')
    .select('*')
    .eq('token', token)
    .maybeSingle()

  // A removed pilot's old link must never re-activate their row (2026-09-17).
  const { data: participant } = invitation?.participant_id
    ? await admin.from('trip_participants').select('status').eq('id', invitation.participant_id).maybeSingle()
    : { data: null }
  const state = invitationAcceptState(invitation, participant)
  if (state === 'expired') {
    return NextResponse.json({ error: 'Invitation is invalid or expired.' }, { status: 404 })
  }
  if (state === 'withdrawn') {
    return NextResponse.json({ error: 'This invitation was withdrawn by the person who sent it.' }, { status: 410 })
  }
  if (state === 'already_accepted') {
    return NextResponse.json({ ok: true, trip_id: invitation!.trip_id })
  }

  // Link (or create) the participant row for this user.
  let acceptedRow: TripParticipant | null = null
  if (invitation.participant_id) {
    const { data } = await admin
      .from('trip_participants')
      .update({ user_id: user.id, status: 'active' })
      .eq('id', invitation.participant_id)
      .select('*')
      .maybeSingle()
    acceptedRow = (data as TripParticipant | null) ?? null
  } else {
    const upsertRow = {
      trip_id: invitation.trip_id,
      user_id: user.id,
      email: invitation.email,
      name: user.name,
      role: invitation.role,
      status: 'active',
      addition_method: 'invitation_accepted',
    }
    let up = await admin.from('trip_participants').upsert(upsertRow, { onConflict: 'trip_id,email,role' }).select('*').maybeSingle()
    if (up.error?.message.includes('addition_method')) {
      const { addition_method: _m, ...legacy } = upsertRow
      void _m
      up = await admin.from('trip_participants').upsert(legacy, { onConflict: 'trip_id,email,role' }).select('*').maybeSingle()
    }
    acceptedRow = (up.data as TripParticipant | null) ?? null
  }

  await admin
    .from('trip_invitations')
    .update({ accepted_at: new Date().toISOString(), accepted_by: user.id })
    .eq('id', invitation.id)

  await logTripEvent({
    tripId: invitation.trip_id,
    actorId: user.id,
    actorLabel: user.name || user.email,
    action: 'invitation_accepted',
    detail: { role: invitation.role },
  })

  // A joining dispatcher with exactly one carrier relation attaches that
  // carrier to the trip by default (Nash, 2026-09-19). With several, the
  // Overview asks them to choose; with none, nothing changes.
  if (invitation.role === 'dispatcher') {
    const { data: trip } = await admin.from('trips').select('id, carrier_company_id, carrier_name').eq('id', invitation.trip_id).maybeSingle()
    const relations = (await carrierCompaniesForUsers([user.id])).get(user.id) ?? []
    const resolution = resolveCarrier({
      assigned: trip?.carrier_company_id ? { id: trip.carrier_company_id, name: trip.carrier_name ?? '', mc: null, dot: null } : null,
      hasDispatcherAccount: true,
      dispatcherCarriers: relations,
      tripCarrierName: trip?.carrier_name,
    })
    if (resolution.kind === 'auto') {
      await assignTripCarrier({ tripId: invitation.trip_id, carrier: resolution.carrier, actorId: user.id, actorLabel: user.name || user.email, method: 'auto' })
    }
  }

  // Auto-Participants (2026-09-30): the person is now on the trip for real.
  if (acceptedRow) {
    await evaluateParticipantRules({ tripId: invitation.trip_id, participant: acceptedRow, trigger: 'participation', session: { id: user.id, originId: user.originId, preview: user.previewWorkspace, contextKey: user.contextKey } })
  }

  return NextResponse.json({ ok: true, trip_id: invitation.trip_id })
}
