import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getSessionUser } from '@/lib/auth'
import { createAdminClient } from '@/lib/supabase/admin'
import { logTripEvent } from '@/lib/audit'

/**
 * Controlled change of the permit-handling mode / payment responsibility
 * (order-intake doc §21): "This should not be casual." Admin only for now —
 * the doc also allows "Broker Admin, or authorized internal support"; those
 * finer roles are backend-later (same pattern as the moderator roles).
 * Every change logs who, old value, new value, and the REQUIRED reason.
 * Follow-up emails = email backend (TODO).
 */

const schema = z
  .object({
    permit_policy: z.enum(['synchron_required', 'upload_allowed']).optional(),
    payment_responsible_party: z.enum(['broker', 'carrier']).optional(),
    // Required when CHANGING a mode (§21); the broker's first choice on a
    // trip created without one (2026-09-19) needs no reason.
    reason: z.string().trim().max(400).optional().or(z.literal('')),
  })
  .refine((v) => v.permit_policy !== undefined || v.payment_responsible_party !== undefined, {
    message: 'Nothing to change.',
  })

export async function PATCH(req: NextRequest, ctx: { params: Promise<{ id: string }> }) {
  const { id: tripId } = await ctx.params
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })

  const parsed = schema.safeParse(await req.json().catch(() => ({})))
  if (!parsed.success) {
    return NextResponse.json(
      { error: parsed.error.issues[0]?.message ?? 'Invalid change.' },
      { status: 400 },
    )
  }
  const input = parsed.data

  const admin = createAdminClient()
  const { data: trip } = await admin
    .from('trips')
    .select('*')
    .eq('id', tripId)
    .maybeSingle()
  if (!trip) return NextResponse.json({ error: 'Trip not found.' }, { status: 404 })

  // Who may decide: an admin always (with a reason). The trip's broker makes
  // the FIRST choice on a trip that has none yet (Nash, 2026-09-19: "he can
  // do his choice what he wants to do with this trip later").
  const isAdmin = user.role === 'admin'
  if (!isAdmin) {
    const { data: me } = await admin
      .from('trip_participants')
      .select('role, status')
      .eq('trip_id', tripId)
      .eq('user_id', user.id)
      .eq('role', 'broker')
      .eq('status', 'active')
      .maybeSingle()
    if (!me || trip.permit_policy) {
      return NextResponse.json(
        { error: trip.permit_policy ? 'Only an admin can change the permit handling mode once it is set.' : 'Only the trip’s broker can choose the permit handling.' },
        { status: 403 },
      )
    }
  } else if ((input.reason ?? '').trim().length < 3 && trip.permit_policy) {
    return NextResponse.json({ error: 'A reason for the change is required.' }, { status: 400 })
  }

  const newPolicy = input.permit_policy ?? trip.permit_policy
  // Switching TO the Synchron flow requires a payment party; switching away
  // clears it ("update payment responsibility if needed", §21).
  let newPayment =
    input.payment_responsible_party ?? trip.payment_responsible_party ?? null
  if (newPolicy === 'synchron_required' && !newPayment) {
    return NextResponse.json(
      { error: 'Choose who will pay Synchron Permits for this permit order.' },
      { status: 400 },
    )
  }
  if (newPolicy === 'upload_allowed') newPayment = null

  const updates: Record<string, unknown> = { permit_policy: newPolicy }
  let paymentChanged = newPayment !== (trip.payment_responsible_party ?? null)
  if (paymentChanged) updates.payment_responsible_party = newPayment
  let { error } = await admin.from('trips').update(updates).eq('id', tripId)
  if (error?.message.includes('payment_responsible_party')) {
    // Graceful until migration 0008 adds the column — the payment value was
    // NOT stored, so don't log a payment change.
    paymentChanged = false
    const retry = await admin
      .from('trips')
      .update({ permit_policy: newPolicy })
      .eq('id', tripId)
    error = retry.error
  }
  if (error) {
    return NextResponse.json({ error: 'Could not save the change.' }, { status: 500 })
  }

  const actorLabel = user.name || user.email
  if (newPolicy !== trip.permit_policy) {
    await logTripEvent({
      tripId,
      actorId: user.id,
      actorLabel,
      action: 'permit_handling_changed',
      detail: { from: trip.permit_policy, to: newPolicy, reason: input.reason || (trip.permit_policy ? null : 'initial choice by the broker') },
    })
  }
  if (paymentChanged) {
    await logTripEvent({
      tripId,
      actorId: user.id,
      actorLabel,
      action: 'payment_responsibility_changed',
      detail: {
        from: trip.payment_responsible_party ?? null,
        to: newPayment,
        reason: input.reason || null,
      },
    })
  }
  // TODO(backend): send the correct follow-up email for the new workflow.

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