import { NextRequest, NextResponse } from 'next/server'
import { createAdminClient } from '@/lib/supabase/admin'
import { requireParticipant } from '@/lib/api-guard'
import { canUploadDocuments } from '@/lib/domain/permissions'
import { extractPermit } from '@/lib/adapters/flask'
import { computePermitWarnings } from '@/lib/domain/warnings'
import { statusAfterPermitProcessed } from '@/lib/domain/status'
import { logTripEvent } from '@/lib/audit'

export const runtime = 'nodejs'
export const maxDuration = 120

const MAX_FILE_BYTES = 25 * 1024 * 1024
// Users upload only rate cons, permits, and supporting docs ('other').
// Provisions come from Synchron; routes are never uploaded.
const KINDS = new Set(['rate_confirmation', 'permit', 'other'])

/** Upload a document to a trip. Permit uploads run extraction and may activate the trip. */
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

  if (!canUploadDocuments(participant.role)) {
    return NextResponse.json({ error: 'Your role cannot upload documents.' }, { status: 403 })
  }

  const form = await req.formData()
  const file = form.get('file')
  const kind = String(form.get('kind') ?? 'other')
  if (!(file instanceof File) || file.size === 0 || file.size > MAX_FILE_BYTES) {
    return NextResponse.json({ error: 'A file up to 25MB is required.' }, { status: 400 })
  }
  if (!KINDS.has(kind)) {
    return NextResponse.json({ error: 'Invalid document kind.' }, { status: 400 })
  }

  const admin = createAdminClient()

  // Synchron flow lockdown (order-intake doc §6/§18 — enforced server-side,
  // not just hidden in the UI): when the broker chose Synchron processing,
  // permits are uploaded by Synchron through API, never manually.
  if (kind === 'permit' && participant.role !== 'admin') {
    const { data: policyRow } = await admin
      .from('trips')
      .select('permit_policy')
      .eq('id', tripId)
      .single()
    if (policyRow?.permit_policy === 'synchron_required') {
      return NextResponse.json(
        { error: 'Permits for this trip are processed and uploaded by Synchron Permits.' },
        { status: 403 },
      )
    }
  }
  const path = `${tripId}/${crypto.randomUUID()}-${file.name.replace(/[^\w.\-]/g, '_')}`
  const { error: upErr } = await admin.storage
    .from('trip-documents')
    .upload(path, file, { contentType: file.type })
  if (upErr) {
    return NextResponse.json({ error: 'Upload failed. Try again.' }, { status: 500 })
  }

  const label = participant.name || user.email || 'participant'
  const { data: doc, error: docErr } = await admin
    .from('documents')
    .insert({
      trip_id: tripId,
      kind,
      storage_path: path,
      file_name: file.name,
      mime_type: file.type,
      size_bytes: file.size,
      uploaded_by: user.id,
      uploader_label: label,
    })
    .select()
    .single()
  if (docErr || !doc) {
    return NextResponse.json({ error: 'Could not record the document.' }, { status: 500 })
  }

  await logTripEvent({
    tripId,
    actorId: user.id,
    actorLabel: label,
    action: 'document_uploaded',
    detail: { kind, file_name: file.name },
  })

  let extractionNote: string | null = null

  if (kind === 'permit') {
    const ex = await extractPermit(file, file.name)
    const p = ex.ok ? ex.data! : undefined
    const { data: permit } = await admin
      .from('permits')
      .insert({
        trip_id: tripId,
        document_id: doc.id,
        state_code: p?.state_code ?? '',
        permit_number: p?.permit_number ?? null,
        effective_date: p?.effective_date ?? null,
        expiration_date: p?.expiration_date ?? null,
        permit_length_in: p?.length_in ?? null,
        permit_width_in: p?.width_in ?? null,
        permit_height_in: p?.height_in ?? null,
        permit_weight_lbs: p?.weight_lbs ?? null,
        extraction: p ? { ...p } : null,
        extraction_status: ex.ok ? 'processed' : 'pending',
      })
      .select()
      .single()

    if (!ex.ok) {
      extractionNote =
        'Permit stored. Automatic extraction is pending (AI service not reachable) — details can be reviewed manually.'
    }

    if (permit && ex.ok) {
      const { data: trip } = await admin.from('trips').select('*').eq('id', tripId).single()
      if (trip) {
        // Sibling permits: a still-valid duplicate for the same state
        // suppresses the expiration alert (Nash's multiple-permits rule).
        const { data: siblings } = await admin
          .from('permits')
          .select('id, state_code, effective_date, expiration_date')
          .eq('trip_id', tripId)
        const warnings = computePermitWarnings(trip, permit, new Date(), siblings ?? [])
        if (warnings.length > 0) {
          await admin.from('warnings').insert(
            warnings.map((w) => ({
              trip_id: tripId,
              permit_id: w.permitId ?? null,
              kind: w.kind,
              severity: w.severity,
              message: w.message,
            })),
          )
        }
        const nextStatus = statusAfterPermitProcessed(trip.status)
        if (nextStatus !== trip.status) {
          await admin.from('trips').update({ status: nextStatus }).eq('id', tripId)
          await logTripEvent({
            tripId,
            actorLabel: 'system',
            action: 'status_changed',
            detail: { from: trip.status, to: nextStatus, reason: 'permit_processed' },
          })
        }
      }
    }
  }

  return NextResponse.json({ ok: true, document_id: doc.id, note: extractionNote })
}
