import 'server-only'

/**
 * Adapter to the EXISTING Flask/MongoDB backend (permit extraction, AI chat,
 * regulations, voice, Synchron/TMS integrations). We reuse that code through
 * this HTTP boundary instead of rewriting it.
 *
 * Contract: docs/FLASK_ADAPTER.md. Configure via env:
 *   FLASK_API_BASE_URL  e.g. https://api.internal.example.com
 *   FLASK_API_KEY       bearer token (optional, if the Flask app requires it)
 *
 * Every method degrades gracefully when the backend is unreachable or not yet
 * configured: callers receive { ok: false, error } and the UI shows an honest
 * "processing pending" state instead of fake data.
 */

export interface AdapterResult<T> {
  ok: boolean
  data?: T
  error?: string
}

export interface PermitExtraction {
  state_code?: string
  permit_number?: string
  effective_date?: string // YYYY-MM-DD
  expiration_date?: string // YYYY-MM-DD
  length_in?: number
  width_in?: number
  height_in?: number
  weight_lbs?: number
  route_description?: string
  restrictions?: string[]
  curfews?: string[]
  escorts?: string[]
  raw?: Record<string, unknown>
}

export interface RateConExtraction {
  origin?: string
  destination?: string
  commodity?: string
  carrier_name?: string
  broker_name?: string
  pickup_date?: string
  delivery_date?: string
  length_in?: number
  width_in?: number
  height_in?: number
  weight_lbs?: number
  raw?: Record<string, unknown>
}

export interface AiAnswer {
  answer: string
  confidence?: 'high' | 'partial' | 'low'
  sources?: string[]
}

export function isFlaskConfigured(): boolean {
  return Boolean(process.env.FLASK_API_BASE_URL)
}

async function callFlask<T>(
  path: string,
  init: RequestInit & { timeoutMs?: number } = {},
): Promise<AdapterResult<T>> {
  const base = process.env.FLASK_API_BASE_URL
  if (!base) {
    return { ok: false, error: 'FLASK_API_BASE_URL not configured' }
  }
  const { timeoutMs = 60_000, ...rest } = init
  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort(), timeoutMs)
  try {
    const res = await fetch(`${base.replace(/\/$/, '')}${path}`, {
      ...rest,
      signal: controller.signal,
      headers: {
        ...(rest.body instanceof FormData ? {} : { 'Content-Type': 'application/json' }),
        ...(process.env.FLASK_API_KEY
          ? { Authorization: `Bearer ${process.env.FLASK_API_KEY}` }
          : {}),
        ...(rest.headers ?? {}),
      },
    })
    if (!res.ok) {
      return { ok: false, error: `Backend responded ${res.status}` }
    }
    return { ok: true, data: (await res.json()) as T }
  } catch (err) {
    return { ok: false, error: err instanceof Error ? err.message : 'Backend unreachable' }
  } finally {
    clearTimeout(timer)
  }
}

/** Extract structured data from a permit PDF/image. */
export async function extractPermit(
  file: Blob,
  fileName: string,
): Promise<AdapterResult<PermitExtraction>> {
  const form = new FormData()
  form.append('file', file, fileName)
  return callFlask<PermitExtraction>('/api/extract/permit', {
    method: 'POST',
    body: form,
    timeoutMs: 120_000,
  })
}

/** Extract structured data from a rate confirmation. */
export async function extractRateConfirmation(
  file: Blob,
  fileName: string,
): Promise<AdapterResult<RateConExtraction>> {
  const form = new FormData()
  form.append('file', file, fileName)
  return callFlask<RateConExtraction>('/api/extract/rate-confirmation', {
    method: 'POST',
    body: form,
    timeoutMs: 120_000,
  })
}

/**
 * Ask the trip-context AI a question (permit / provisions / curfew / escort /
 * validity / dimensions). Context is assembled by the caller from Supabase so
 * one trip's data is never mixed with another ("one trip, one context").
 */
export async function askTripAi(payload: {
  question: string
  state_code?: string | null
  language?: string
  trip: {
    ref_code: string
    origin: string
    destination: string
    commodity: string
    load_dims: {
      length_in: number | null
      width_in: number | null
      height_in: number | null
      weight_lbs: number | null
    }
  }
  permits: Array<{
    state_code: string
    permit_number: string | null
    effective_date: string | null
    expiration_date: string | null
    extraction: Record<string, unknown> | null
  }>
}): Promise<AdapterResult<AiAnswer>> {
  return callFlask<AiAnswer>('/api/ai/ask', {
    method: 'POST',
    body: JSON.stringify(payload),
    timeoutMs: 90_000,
  })
}

/**
 * Everything a permit office needs, straight from the trip and My Unit
 * (Task 75). Nash: "it will include all the information from My Unit. So the
 * trip commodity, overall dimensions, axle spacings, axle weights, truck
 * trailer information will be included."
 */
export interface SynchronTripData {
  commodity: string
  load: { length_in: number | null; width_in: number | null; height_in: number | null; weight_lbs: number | null }
  overall: { length_in: number | null; width_in: number | null; height_in: number | null; weight_lbs: number | null }
  unit: {
    axle_count: number | null
    axle_spacings_in: number[] | null
    kingpin_to_rear_axle_in: number | null
    axle_weights_lbs: number[] | null
    truck: { unit_number: string | null; vin: string | null; make: string | null; model: string | null; year: number | null }
    trailer: { unit_number: string | null; vin: string | null; make: string | null; model: string | null; year: number | null; axle_count: number | null }
  } | null
  /** The expired permit being re-ordered, when this is a re-order. */
  replaces_permit: { state_code: string; permit_number: string | null; expiration_date: string | null } | null
}

/** Create a permit or route order in Synchron via the existing integration. */
export async function createSynchronOrder(payload: {
  type: 'permit' | 'route'
  trip_ref: string
  state_code?: string | null
  carrier_name: string
  /** The client for this order = the person who made the request (Task 75). */
  contact_email: string
  contact_name?: string
  /** Who Synchron bills: the requester, or the broker/carrier a broker chose. */
  payer?: 'requester' | 'broker' | 'carrier' | null
  notes?: string | null
  /** Signed links — for a permit re-order, the expired permit PDF. */
  document_urls?: string[]
  trip_data?: SynchronTripData
}): Promise<AdapterResult<{ order_id?: string }>> {
  return callFlask<{ order_id?: string }>('/api/synchron/orders', {
    method: 'POST',
    body: JSON.stringify(payload),
  })
}
