import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createAdminClient } from '@/lib/supabase/admin'
import { requireParticipant } from '@/lib/api-guard'
import { createSynchronOrder, type SynchronTripData } from '@/lib/adapters/flask'
import { isMissingColumn } from '@/lib/db-compat'
import { logTripEvent } from '@/lib/audit'
import type { Permit, Trip, TripUnit } 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(),
})

/**
 * 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'

  // 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 baseRow = {
    trip_id: tripId,
    type: input.type,
    state_code: input.state_code || replacedPermit?.state_code || null,
    notes: input.notes || null,
    requested_by: user.id,
    requester_label: label,
    route_type: input.route_type ?? null,
    notify: input.notify ?? null,
  }
  const newColumns = {
    paid_with: input.type === 'route_request' ? (input.paid_with ?? null) : null,
    payer,
    replaces_permit_id: replacedPermit?.id ?? null,
  }

  let { data: request, error } = await admin
    .from('service_requests')
    .insert({ ...baseRow, ...newColumns })
    .select()
    .single()
  if (isMissingColumn(error, 'paid_with', 'payer', 'replaces_permit_id')) {
    // Migration 0011 not applied — record the request without the new
    // columns rather than losing the order.
    ;({ data: request, error } = await admin.from('service_requests').insert(baseRow).select().single())
  }
  if (error || !request) {
    return NextResponse.json({ error: 'Could not create the request.' }, { status: 500 })
  }

  const { data: tripRow } = await admin.from('trips').select('*').eq('id', tripId).single()
  const trip = tripRow as Trip | null

  // Permit orders carry the full unit sheet and, for a re-order, the expired
  // PDF — "I think that's going to help to speed up the process."
  let tripData: SynchronTripData | undefined
  const documentUrls: string[] = []
  if (input.type === 'permit_request' && trip) {
    const { data: unitRow } = await admin.from('trip_units').select('*').eq('trip_id', tripId).maybeSingle()
    const unit = (unitRow ?? null) as TripUnit | null
    tripData = {
      commodity: trip.commodity,
      load: {
        length_in: trip.load_length_in,
        width_in: trip.load_width_in,
        height_in: trip.load_height_in,
        weight_lbs: trip.load_weight_lbs,
      },
      overall: {
        length_in: trip.overall_length_in,
        width_in: trip.overall_width_in,
        height_in: trip.overall_height_in,
        weight_lbs: trip.overall_weight_lbs,
      },
      unit: unit
        ? {
            axle_count: unit.axle_count,
            axle_spacings_in: unit.axle_spacings_in,
            kingpin_to_rear_axle_in: unit.kingpin_to_rear_axle_in ?? null,
            axle_weights_lbs: unit.axle_weights_lbs,
            truck: {
              unit_number: unit.truck_unit_number,
              vin: unit.truck_vin,
              make: unit.truck_make,
              model: unit.truck_model,
              year: unit.truck_year,
            },
            trailer: {
              unit_number: unit.trailer_unit_number,
              vin: unit.trailer_vin,
              make: unit.trailer_make,
              model: unit.trailer_model,
              year: unit.trailer_year,
              axle_count: unit.trailer_axle_count,
            },
          }
        : null,
      replaces_permit: replacedPermit
        ? {
            state_code: replacedPermit.state_code,
            permit_number: replacedPermit.permit_number,
            expiration_date: replacedPermit.expiration_date,
          }
        : null,
    }
    if (replacedPermit?.document_id) {
      const { data: doc } = await admin
        .from('documents')
        .select('storage_path')
        .eq('id', replacedPermit.document_id)
        .maybeSingle()
      if (doc) {
        const { data: signed } = await admin.storage
          .from('trip-documents')
          .createSignedUrl(doc.storage_path, 60 * 60 * 24 * 7)
        if (signed?.signedUrl) documentUrls.push(signed.signedUrl)
      }
    }
  }

  const order = await createSynchronOrder({
    type: input.type === 'permit_request' ? 'permit' : 'route',
    trip_ref: trip?.ref_code ?? tripId,
    state_code: baseRow.state_code,
    carrier_name: trip?.carrier_name ?? '',
    contact_email: user.email ?? participant.email,
    contact_name: label,
    payer,
    notes: input.notes || null,
    ...(documentUrls.length ? { document_urls: documentUrls } : {}),
    ...(tripData ? { trip_data: tripData } : {}),
  })
  // Task 84: keep Synchron's order number so the workspace can show
  // "Order #…" — it was returned and thrown away before. Column arrives with
  // migration 0013; ignore the write until then.
  const vendorOrderId = order.ok ? (order.data?.order_id ?? null) : null
  if (vendorOrderId) {
    const { error: idError } = await admin
      .from('service_requests')
      .update({ vendor_order_id: vendorOrderId })
      .eq('id', request.id)
    if (idError && !isMissingColumn(idError, 'vendor_order_id')) {
      console.error('vendor_order_id not saved', idError.message)
    } else if (!idError) {
      request = { ...request, vendor_order_id: vendorOrderId }
    }
  }

  await logTripEvent({
    tripId,
    actorId: user.id,
    actorLabel: label,
    action: 'service_requested',
    detail: {
      type: input.type,
      state_code: baseRow.state_code,
      ...(newColumns.paid_with ? { paid_with: newColumns.paid_with } : {}),
      ...(payer ? { payer } : {}),
      ...(replacedPermit ? { replaces_permit: replacedPermit.permit_number ?? replacedPermit.id } : {}),
    },
  })

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