import { processWorkspacePermit } from '@/lib/data/permit-processing'
import { NextRequest, NextResponse } from 'next/server'
import { createAdminClient } from '@/lib/supabase/admin'
import { publicOrigin } from '@/lib/app-url'
import { requireParticipant } from '@/lib/api-guard'
import { canUploadDocuments } from '@/lib/domain/permissions'
import { extractRateConfirmation } from '@/lib/adapters/flask'
import { logTripEvent } from '@/lib/audit'
import { syncTripToHha } from '@/lib/integrations/hha-trip-sync'
import { deleteS3Object, S3_PREFIX, uploadFileToS3 } from '@/lib/storage/s3'

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

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'])
const ALLOWED_MIME = new Set([
  'application/pdf',
  'image/jpeg',
  'image/png',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
])

/** 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 })
  }
  if (!ALLOWED_MIME.has(file.type)) {
    return NextResponse.json({ error: 'Use a PDF, JPG, PNG or DOCX file.' }, { status: 415 })
  }

  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 prefix = kind === 'rate_confirmation'
    ? S3_PREFIX.rateConfirmation
    : kind === 'permit'
      ? S3_PREFIX.permit
      : S3_PREFIX.tripSupporting
  let stored
  try {
    stored = await uploadFileToS3(file, file.name, prefix)
  } catch (error) {
    console.error('S3 document upload failed:', error instanceof Error ? error.message : error)
    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_provider: 's3',
      storage_path: stored.key,
      external_url: stored.url,
      file_name: file.name,
      mime_type: stored.contentType,
      size_bytes: file.size,
      uploaded_by: user.id,
      uploader_label: label,
    })
    .select()
    .single()
  if (docErr || !doc) {
    await deleteS3Object(stored.key).catch(() => undefined)
    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 === 'rate_confirmation') {
    const ex = await extractRateConfirmation(file, file.name, {
      tripId,
      documentId: doc.id,
      sourceUrl: stored.url,
    })
    if (ex.ok && ex.data) {
      const rc = ex.data
      const updates = Object.fromEntries(
        Object.entries({
          origin: rc.origin,
          destination: rc.destination,
          commodity: rc.commodity,
          carrier_name: rc.carrier_name,
          pickup_date: rc.pickup_date,
          delivery_date: rc.delivery_date,
          load_length_in: rc.length_in,
          load_width_in: rc.width_in,
          load_height_in: rc.height_in,
          load_weight_lbs: rc.weight_lbs,
        }).filter(([, value]) => value !== undefined),
      )
      if (Object.keys(updates).length > 0) {
        await admin.from('trips').update(updates).eq('id', tripId)
      }
    } else {
      extractionNote =
        'Rate confirmation stored. Automatic extraction is pending — details can be reviewed manually.'
    }
  }

  if (kind === 'permit') {
    const { data: permit, error } = await admin.from('permits').insert({
      trip_id: tripId, document_id: doc.id, state_code: '', extraction_status: 'pending',
    }).select('id').single()
    if (error || !permit) {
      return NextResponse.json({ error: 'File saved, but permit could not be queued. Contact support.', document_id: doc.id }, { status: 503 })
    }
    const result = await processWorkspacePermit({ permitId: permit.id, file, origin: publicOrigin(req) })
    if (!result.ok) extractionNote = 'Permit saved. Processing is pending and will retry automatically.'
    else if (result.status !== 'ready') extractionNote = 'Permit saved. Route preparation is pending; no credits have been deducted.'
  }

  const sync = await syncTripToHha(tripId)
  if (!sync.ok) console.error('Final document sync failed:', sync.error)

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