import { NextRequest, NextResponse } from 'next/server'
import { getSessionUser } from '@/lib/auth'
import { createAdminClient } from '@/lib/supabase/admin'
import { evaluateParticipantRules } from '@/lib/data/auto-participants'
import type { TripParticipant } from '@/types/db'
import { extractRateConfirmation } from '@/lib/adapters/flask'
import { generateRefCode } from '@/lib/domain/refcode'
import { logTripEvent } from '@/lib/audit'
import { deleteS3Object, S3_PREFIX, uploadFileToS3 } from '@/lib/storage/s3'

export const runtime = 'nodejs'
export const maxDuration = 300

/**
 * Freight Broker · New Trip (Nash, 2026-09-19): "only two sections — the
 * top one is the rate confirmation, part two drag and drop the permits, and
 * create the trip. He can invite later, and choose what he wants to do with
 * this trip later. Maybe he's just creating a trip that was already
 * completed for him to analyze it."
 *
 * Creates the broker's own trip from the rate confirmation alone: no
 * dispatcher, no permit-handling decision (permit_policy stays null until
 * the broker chooses in the workspace). Lane / commodity / dimensions come
 * from the rate-con extractor when it is configured, else stay blank for
 * the workspace to fill. Permits are uploaded next by the page through
 * /api/trips/[id]/documents, which runs extraction and warnings.
 */
const MAX_FILE_BYTES = 25 * 1024 * 1024
const ALLOWED_MIME = new Set([
  'application/pdf', 'image/jpeg', 'image/png',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
])
const validFile = (f: File) => f.size > 0 && f.size <= MAX_FILE_BYTES && ALLOWED_MIME.has(f.type)

export async function POST(req: NextRequest) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })
  if (user.role !== 'broker' && user.role !== 'admin') {
    return NextResponse.json({ error: 'Only a freight broker creates trips here.' }, { status: 403 })
  }
  const form = await req.formData()
  const rateCon = form.get('rate_confirmation')
  if (!(rateCon instanceof File) || !validFile(rateCon)) {
    return NextResponse.json({ error: 'A rate confirmation file (PDF/JPG/PNG/DOCX, max 25MB) is required.' }, { status: 400 })
  }
  const notes = String(form.get('notes') ?? '').trim().slice(0, 2000)

  let stored
  try {
    stored = await uploadFileToS3(rateCon, rateCon.name, S3_PREFIX.rateConfirmation)
  } catch (error) {
    console.error('S3 rate confirmation upload failed:', error instanceof Error ? error.message : error)
    return NextResponse.json({ error: 'Could not store the rate confirmation. Try again.' }, { status: 500 })
  }

  const admin = createAdminClient()
  const { data: trip, error } = await admin
    .from('trips')
    .insert({
      ref_code: generateRefCode(),
      created_by: user.id,
      status: 'waiting_for_permits',
      permit_source: 'upload',
      permit_policy: null,
      carrier_name: '',
      origin: '',
      destination: '',
      commodity: '',
      load_length_in: null,
      load_width_in: null,
      load_height_in: null,
      load_weight_lbs: null,
      pickup_date: null,
      delivery_date: null,
      notes: notes || null,
    })
    .select()
    .single()
  if (error || !trip) {
    await deleteS3Object(stored.key).catch(() => undefined)
    return NextResponse.json({ error: 'Could not create the trip. Try again.' }, { status: 500 })
  }

  const creatorRow = {
    trip_id: trip.id, user_id: user.id, email: user.email, name: user.name, role: user.role === 'admin' ? 'admin' : 'broker', status: 'active', addition_method: 'trip_creator',
  }
  let creator = await admin.from('trip_participants').insert(creatorRow).select('*').maybeSingle()
  if (creator.error?.message.includes('addition_method')) {
    const { addition_method: _m, ...legacy } = creatorRow
    void _m
    creator = await admin.from('trip_participants').insert(legacy).select('*').maybeSingle()
  }
  // Auto-Participants (2026-09-30): the broker's rules fire in the mode they created the trip in.
  if (creator.data) {
    await evaluateParticipantRules({ tripId: trip.id, participant: creator.data as TripParticipant, trigger: 'participation', session: { id: user.id, originId: user.originId, preview: user.previewWorkspace, contextKey: user.contextKey } })
  }

  const { data: doc, error: docError } = await admin.from('documents').insert({
    trip_id: trip.id,
    kind: 'rate_confirmation',
    storage_provider: 's3',
    storage_path: stored.key,
    external_url: stored.url,
    file_name: rateCon.name,
    mime_type: stored.contentType,
    size_bytes: rateCon.size,
    uploaded_by: user.id,
    uploader_label: user.name || user.email,
  }).select('id').single()
  if (docError || !doc) {
    await deleteS3Object(stored.key).catch(() => undefined)
    return NextResponse.json({ error: 'Could not record the rate confirmation.' }, { status: 500 })
  }

  const extraction = await extractRateConfirmation(rateCon, rateCon.name, {
    tripId: trip.id,
    documentId: doc.id,
    sourceUrl: stored.url,
  })
  const rc = extraction.ok ? extraction.data : undefined
  if (rc) {
    await admin.from('trips').update({
      carrier_name: rc.carrier_name ?? '',
      origin: rc.origin ?? '',
      destination: rc.destination ?? '',
      commodity: rc.commodity ?? '',
      load_length_in: rc.length_in ?? null,
      load_width_in: rc.width_in ?? null,
      load_height_in: rc.height_in ?? null,
      load_weight_lbs: rc.weight_lbs ?? null,
      pickup_date: rc.pickup_date ?? null,
      delivery_date: rc.delivery_date ?? null,
    }).eq('id', trip.id)
  }

  await logTripEvent({
    tripId: trip.id, actorId: user.id, actorLabel: user.name || user.email, action: 'trip_created',
    detail: { via: 'broker_new_trip', rate_confirmation: rateCon.name, extracted: extraction.ok, origin: rc?.origin ?? '', destination: rc?.destination ?? '' },
  })

  return NextResponse.json({ ok: true, trip_id: trip.id, trip_ref: trip.ref_code, extracted: extraction.ok, rate_con_stored: true })
}
