import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createAdminClient } from '@/lib/supabase/admin'
import { requireParticipant } from '@/lib/api-guard'
import { canActivateTrip, canManageStatus, canTransition } from '@/lib/domain/status'
import { isMissingColumn } from '@/lib/db-compat'
import { logTripEvent } from '@/lib/audit'
import type { TripStatus } from '@/types/db'

/**
 * Trip status.
 *
 * Two scopes, both kept on purpose (client decision, 2026-09-07):
 *
 *   scope 'trip' — the original trip-wide change (complete, cancel, reopen).
 *     Still broker / dispatcher / admin only, still transition-validated.
 *
 *   scope 'me'   — completion for the caller ALONE. Nash: "this marks it
 *     complete for me as the user… when you complete the trip in a workspace,
 *     it completes it only for you, and it gives an option for others to
 *     complete it also if they want to. But I don't want to force close,
 *     force complete for all users this trip." Every role may do this,
 *     including the driver, who cannot change trip-wide status.
 */

const schema = z.discriminatedUnion('scope', [
  z.object({
    scope: z.literal('trip'),
    to: z.enum(['draft', 'waiting_for_permits', 'active', 'completed', 'cancelled']),
  }),
  z.object({
    scope: z.literal('me'),
    // 'active' clears a personal completion — the driver can re-activate a
    // trip he completed. 'dismiss_prompt' is the "No" answer to the
    // "somebody marked this completed" question.
    to: z.enum(['completed', 'active', 'dismiss_prompt']),
  }),
])

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 raw = await req.json().catch(() => ({}))
  // Callers that predate the per-user scope send only { to } — treat those as
  // the trip-wide change they have always been.
  const parsed = schema.safeParse({ scope: 'trip', ...raw })
  if (!parsed.success) return NextResponse.json({ error: 'Invalid status.' }, { status: 400 })
  const input = parsed.data

  const admin = createAdminClient()

  /* ---------------- Personal completion ---------------- */
  if (input.scope === 'me') {
    const patch =
      input.to === 'dismiss_prompt'
        ? { completion_prompt_dismissed_at: new Date().toISOString() }
        : {
            completed_at: input.to === 'completed' ? new Date().toISOString() : null,
            // Answering by completing also settles the prompt.
            completion_prompt_dismissed_at:
              input.to === 'completed' ? new Date().toISOString() : null,
          }

    const { error } = await admin
      .from('trip_participants')
      .update(patch)
      .eq('id', participant.id)

    if (isMissingColumn(error, 'completed_at', 'completion_prompt_dismissed_at')) {
      return NextResponse.json(
        { error: 'Personal trip completion needs database migration 0010.' },
        { status: 503 },
      )
    }
    if (error) {
      return NextResponse.json({ error: 'Could not update your trip status.' }, { status: 500 })
    }

    if (input.to !== 'dismiss_prompt') {
      await logTripEvent({
        tripId,
        actorId: user.id,
        actorLabel: participant.name || user.email || 'participant',
        action: input.to === 'completed' ? 'participant_completed' : 'participant_reactivated',
        detail: { role: participant.role },
      })
    }
    return NextResponse.json({ ok: true, scope: 'me', to: input.to })
  }

  /* ---------------- Trip-wide change ---------------- */
  const to = input.to as TripStatus
  const { data: trip } = await admin.from('trips').select('id, status').eq('id', tripId).single()
  if (!trip) return NextResponse.json({ error: 'Trip not found.' }, { status: 404 })
  const current = trip.status as TripStatus

  // Activating a waiting trip is "one push for all members" and open to the
  // driver too (Task 67). Everything else stays broker / dispatcher / admin.
  const activating = to === 'active' && canActivateTrip(participant.role, current)
  if (!activating && !canManageStatus(participant.role)) {
    return NextResponse.json({ error: 'Your role cannot change trip status.' }, { status: 403 })
  }

  if (!canTransition(current, to)) {
    return NextResponse.json(
      { error: `Cannot move a ${trip.status} trip to ${to}.` },
      { status: 400 },
    )
  }

  await admin
    .from('trips')
    .update({ status: to, completed_at: to === 'completed' ? new Date().toISOString() : null })
    .eq('id', tripId)

  await logTripEvent({
    tripId,
    actorId: user.id,
    actorLabel: participant.name || user.email || 'participant',
    action: 'status_changed',
    detail: { from: trip.status, to },
  })

  return NextResponse.json({ ok: true })
}
