import Link from 'next/link'
import { AppShell } from '@/components/app/app-shell'
import { BackLink } from '@/components/app/back-link'
import { requireSurface } from '@/lib/auth/surface-guard'
import { createAdminClient } from '@/lib/supabase/admin'
import { nowMs } from '@/lib/domain/time'
import { FULFILLMENT_STATUS_LABELS, PURCHASE_STATUSES, PURCHASE_STATUS_LABELS } from '@/lib/domain/purchases'
import { formatCents } from '@/lib/domain/routing-products'
import type { PaymentReference, Purchase, PurchaseEvent, PurchaseItem, PurchaseStatus } from '@/types/db'
import { PurchaseActions } from './purchase-actions'

/**
 * Admin — purchase reconciliation (2026-09-29 task §24, Task 11.1).
 *
 * Read model over purchases + purchase_items + payment_references +
 * purchase_events. The only actions are "Re-run reconciliation" and
 * "Flag / clear flag". There is no "mark as paid" here or anywhere else.
 */

type Window = '24h' | '7d' | '30d'
const WINDOW_MS: Record<Window, number> = { '24h': 24 * 60 * 60_000, '7d': 7 * 24 * 60 * 60_000, '30d': 30 * 24 * 60 * 60_000 }
const LIMIT = 200
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

const label = (value: string) => value.replaceAll('_', ' ').replace(/\b\w/g, (letter) => letter.toUpperCase())
const utc = (iso: string | null | undefined) => (iso ? `${new Date(iso).toLocaleString('en-US', { timeZone: 'UTC', hour12: false })} UTC` : '—')
const truncate = (value: string | null | undefined, n = 14) => (!value ? '—' : value.length > n ? `${value.slice(0, n)}…` : value)
const compactDetail = (detail: Record<string, unknown> | null | undefined) =>
  Object.entries(detail ?? {}).map(([k, v]) => `${k}: ${typeof v === 'object' ? JSON.stringify(v) : String(v)}`).join(' · ').slice(0, 400)

const statusClass = (status: PurchaseStatus) => {
  if (status === 'paid') return 'bg-green-50 text-green-700'
  if (status === 'payment_failed' || status === 'cancelled' || status === 'expired') return 'bg-red-50 text-red-700'
  if (status.includes('refund')) return 'bg-violet-50 text-violet-800'
  return 'bg-amber-50 text-amber-800'
}

/**
 * Which local purchase statuses are consistent with the last payment status
 * Synchron reported. Anything else is shown as "Mismatch — review" (visual
 * only; nothing is written from the page loader).
 */
const CONSISTENT: Record<string, readonly PurchaseStatus[]> = {
  pending: ['pending_checkout', 'pending_payment'],
  paid: ['paid', 'refund_pending', 'partially_refunded', 'refunded'],
  failed: ['payment_failed', 'pending_checkout', 'pending_payment', 'cancelled'],
  expired: ['expired', 'pending_checkout', 'cancelled'],
  cancelled: ['cancelled', 'pending_checkout', 'expired'],
  refunded: ['refunded'],
  partially_refunded: ['partially_refunded', 'refunded'],
}
function isMismatch(purchase: Purchase, payment: PaymentReference | null): boolean {
  if (!payment?.payment_status) return false
  const allowed = CONSISTENT[payment.payment_status]
  if (!allowed) return false
  return !allowed.includes(purchase.purchase_status)
}

type Row = {
  purchase: Purchase
  items: PurchaseItem[]
  payment: PaymentReference | null
  events: PurchaseEvent[]
  lastError: PurchaseEvent | null
  tripRef: string | null
  customer: string
  company: string
  mismatch: boolean
}

export default async function AdminPurchasesPage({ searchParams }: {
  searchParams: Promise<{ status?: string | string[]; trip?: string | string[]; flagged?: string | string[]; window?: string | string[] }>
}) {
  const { profile } = await requireSurface('purchases')
  const query = await searchParams
  const pick = (v: string | string[] | undefined) => (typeof v === 'string' ? v : '').trim()
  const selectedWindow = pick(query.window)
  const window: Window = selectedWindow === '24h' || selectedWindow === '30d' ? selectedWindow : '7d'
  const rawStatus = pick(query.status)
  const status: PurchaseStatus | 'all' = (PURCHASE_STATUSES as readonly string[]).includes(rawStatus) ? (rawStatus as PurchaseStatus) : 'all'
  const trip = pick(query.trip).slice(0, 60)
  const flaggedOnly = pick(query.flagged) === '1'
  const since = new Date(nowMs() - WINDOW_MS[window]).toISOString()
  const admin = createAdminClient()

  // Resolve the trip filter (ref_code or uuid) to a trip id first.
  let tripId: string | null = null
  let tripFilterMissing = false
  if (trip) {
    if (UUID_RE.test(trip)) tripId = trip
    else {
      const { data } = await admin.from('trips').select('id').eq('ref_code', trip).maybeSingle()
      tripId = (data as { id: string } | null)?.id ?? null
      if (!tripId) tripFilterMissing = true
    }
  }

  let purchaseQuery = admin.from('purchases').select('*').gte('created_at', since).order('created_at', { ascending: false }).limit(LIMIT)
  if (status !== 'all') purchaseQuery = purchaseQuery.eq('purchase_status', status)
  if (flaggedOnly) purchaseQuery = purchaseQuery.eq('needs_reconciliation', true)
  if (tripId) purchaseQuery = purchaseQuery.eq('hha_trip_id', tripId)
  const purchasesResult = tripFilterMissing ? { data: [], error: null } : await purchaseQuery
  const purchases = (purchasesResult.data ?? []) as Purchase[]
  const ids = purchases.map((p) => p.id)

  const [items, payments, events, trips, profiles, companies] = ids.length
    ? await Promise.all([
        admin.from('purchase_items').select('*').in('purchase_id', ids).order('created_at'),
        admin.from('payment_references').select('*').in('purchase_id', ids).order('created_at', { ascending: false }),
        admin.from('purchase_events').select('*').in('purchase_id', ids).order('created_at', { ascending: false }).limit(2000),
        admin.from('trips').select('id,ref_code').in('id', [...new Set(purchases.map((p) => p.hha_trip_id))]),
        admin.from('profiles').select('id,full_name,email').in('id', [...new Set(purchases.map((p) => p.hha_user_id))]),
        admin.from('companies').select('id,display_name').in('id', [...new Set(purchases.map((p) => p.company_id).filter((c): c is string => !!c))]),
      ])
    : [{ data: [] }, { data: [] }, { data: [] }, { data: [] }, { data: [] }, { data: [] }]

  const permitIds = [...new Set(((items.data ?? []) as PurchaseItem[]).map((i) => i.hha_permit_id).filter((p): p is string => !!p))]
  const permits = permitIds.length ? await admin.from('permits').select('id,state_code').in('id', permitIds) : { data: [] }
  const stateByPermit = new Map<string, string>()
  for (const p of (permits.data ?? []) as Array<{ id: string; state_code: string }>) stateByPermit.set(p.id, p.state_code)

  const itemsBy = new Map<string, PurchaseItem[]>()
  for (const it of (items.data ?? []) as PurchaseItem[]) itemsBy.set(it.purchase_id, [...(itemsBy.get(it.purchase_id) ?? []), it])
  const paymentBy = new Map<string, PaymentReference>()
  for (const p of (payments.data ?? []) as PaymentReference[]) if (!paymentBy.has(p.purchase_id)) paymentBy.set(p.purchase_id, p)
  const eventsBy = new Map<string, PurchaseEvent[]>()
  for (const e of (events.data ?? []) as PurchaseEvent[]) if (e.purchase_id) eventsBy.set(e.purchase_id, [...(eventsBy.get(e.purchase_id) ?? []), e])
  const tripRefs = new Map<string, string>()
  for (const t of (trips.data ?? []) as Array<{ id: string; ref_code: string }>) tripRefs.set(t.id, t.ref_code)
  const profileBy = new Map<string, { full_name: string; email: string }>()
  for (const p of (profiles.data ?? []) as Array<{ id: string; full_name: string; email: string }>) profileBy.set(p.id, p)
  const companyBy = new Map<string, string>()
  for (const c of (companies.data ?? []) as Array<{ id: string; display_name: string }>) companyBy.set(c.id, c.display_name)

  const rows: Row[] = purchases.map((purchase) => {
    const payment = paymentBy.get(purchase.id) ?? null
    const evs = eventsBy.get(purchase.id) ?? []
    const prof = profileBy.get(purchase.hha_user_id)
    return {
      purchase,
      items: itemsBy.get(purchase.id) ?? [],
      payment,
      events: evs,
      lastError: evs.find((e) => e.event === 'synchron_api_error') ?? null,
      tripRef: tripRefs.get(purchase.hha_trip_id) ?? null,
      customer: prof ? `${prof.full_name}${prof.email ? ` <${prof.email}>` : ''}` : purchase.hha_user_id.slice(0, 8),
      company: purchase.company_id ? companyBy.get(purchase.company_id) ?? purchase.company_id.slice(0, 8) : '—',
      mismatch: isMismatch(purchase, payment),
    }
  })

  const mismatches = rows.filter((r) => r.mismatch).length
  const flagged = rows.filter((r) => r.purchase.needs_reconciliation).length

  return (
    <AppShell profile={profile}>
      <main className="mx-auto max-w-7xl space-y-5 px-4 py-8">
        <BackLink />
        <div>
          <h1 className="text-2xl font-bold">Purchases</h1>
          <p className="mt-1 text-sm text-neutral-500">
            Route purchases, Synchron payment references, fulfillment and reconciliation. Payment status is only ever set by a verified Synchron confirmation; there is no manual &quot;mark as paid&quot;. Times are shown in UTC.
          </p>
        </div>
        {purchasesResult.error && <p className="rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900">Purchases could not be loaded. Apply migrations 0045–0047 if they are pending.</p>}
        {tripFilterMissing && <p className="rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900">No trip with reference {trip} was found.</p>}
        <form className="flex flex-wrap items-end gap-3 rounded-xl border bg-white p-4" method="get">
          <label className="text-xs font-semibold text-neutral-600">Window<select name="window" defaultValue={window} className="mt-1 block rounded-md border px-3 py-2 text-sm text-neutral-900"><option value="24h">Last 24 hours</option><option value="7d">Last 7 days</option><option value="30d">Last 30 days</option></select></label>
          <label className="text-xs font-semibold text-neutral-600">Status<select name="status" defaultValue={status} className="mt-1 block rounded-md border px-3 py-2 text-sm text-neutral-900"><option value="all">All</option>{PURCHASE_STATUSES.map((s) => <option key={s} value={s}>{PURCHASE_STATUS_LABELS[s]}</option>)}</select></label>
          <label className="min-w-44 flex-1 text-xs font-semibold text-neutral-600">Trip ref or id<input name="trip" defaultValue={trip} placeholder="HH-20102137" className="mt-1 block w-full rounded-md border px-3 py-2 text-sm text-neutral-900" /></label>
          <label className="flex items-center gap-2 py-2 text-xs font-semibold text-neutral-600"><input type="checkbox" name="flagged" value="1" defaultChecked={flaggedOnly} />Flagged only</label>
          <button className="rounded-md bg-[#0f1b2d] px-4 py-2 text-sm font-semibold text-white">Search</button>
          <Link href="/admin/purchases" className="px-2 py-2 text-sm text-neutral-600 underline">Reset</Link>
        </form>
        <p className="text-xs text-neutral-500">Showing {rows.length} purchases (newest first, up to {LIMIT}) · {flagged} flagged · {mismatches} with a status mismatch.</p>
        <div className="overflow-x-auto rounded-xl border bg-white">
          <table className="min-w-[1400px] w-full text-left text-sm">
            <thead className="border-b bg-neutral-50 text-xs uppercase tracking-wide text-neutral-500"><tr>
              <th className="px-3 py-3">Purchase</th><th className="px-3 py-3">Created</th><th className="px-3 py-3">Customer</th><th className="px-3 py-3">Company</th><th className="px-3 py-3">Trip</th><th className="px-3 py-3">Order token</th><th className="px-3 py-3">Items</th><th className="px-3 py-3">Total</th><th className="px-3 py-3">Status</th><th className="px-3 py-3">Synchron refs</th><th className="px-3 py-3">Last sync</th><th className="px-3 py-3">Flags</th><th className="px-3 py-3">Last error</th><th className="px-3 py-3">Actions</th>
            </tr></thead>
            <tbody className="divide-y">
              {rows.map(({ purchase, items: lines, payment, events: evs, lastError, tripRef, customer, company, mismatch }) => <tr key={purchase.id} className={mismatch ? 'bg-red-50/40' : undefined}>
                <td className="px-3 py-3 align-top">
                  <span className="font-mono text-xs" title={purchase.id}>{purchase.purchase_reference}</span>
                  <details className="mt-1 text-xs">
                    <summary className="cursor-pointer text-neutral-600 underline">Details ({evs.length} events)</summary>
                    <ol className="mt-2 max-h-72 w-[640px] max-w-[70vw] space-y-1 overflow-auto rounded border bg-neutral-50 p-2">
                      {evs.map((e) => <li key={e.id} className="break-words">
                        <span className="text-neutral-500">{utc(e.created_at)}</span> · <span className="font-semibold">{label(e.event)}</span> · {e.source_system}{e.actor_label ? ` · ${e.actor_label}` : ''}{e.external_event_id ? ` · ext ${truncate(e.external_event_id, 20)}` : ''}
                        {Object.keys(e.detail ?? {}).length > 0 && <div className="text-neutral-600">{compactDetail(e.detail)}</div>}
                      </li>)}
                      {!evs.length && <li className="text-neutral-500">No events recorded.</li>}
                    </ol>
                  </details>
                </td>
                <td className="whitespace-nowrap px-3 py-3 align-top text-xs text-neutral-500"><time dateTime={purchase.created_at} title={purchase.created_at}>{utc(purchase.created_at)}</time></td>
                <td className="max-w-48 break-words px-3 py-3 align-top text-xs">{customer}</td>
                <td className="max-w-40 break-words px-3 py-3 align-top text-xs">{company}</td>
                <td className="px-3 py-3 align-top">{tripRef ? <Link className="font-medium underline" href={`/cd-trip-workspace/${encodeURIComponent(tripRef)}`}>{tripRef}</Link> : <span className="font-mono text-xs" title={purchase.hha_trip_id}>{purchase.hha_trip_id.slice(0, 8)}</span>}</td>
                <td className="px-3 py-3 align-top font-mono text-xs">{purchase.synchron_order_token ?? '—'}</td>
                <td className="px-3 py-3 align-top text-xs">
                  {lines.map((it) => <div key={it.id} className="whitespace-nowrap">
                    <span className="font-semibold">{it.hha_permit_id ? stateByPermit.get(it.hha_permit_id) ?? '??' : '—'}</span> · {it.product_code}{it.quantity > 1 ? ` ×${it.quantity}` : ''} · {formatCents(it.line_total_cents, it.currency)} · <span className="text-neutral-600">{FULFILLMENT_STATUS_LABELS[it.fulfillment_status] ?? label(it.fulfillment_status)}</span>
                  </div>)}
                  {!lines.length && '—'}
                </td>
                <td className="whitespace-nowrap px-3 py-3 align-top font-medium">{formatCents(purchase.total_amount_cents, purchase.currency)}</td>
                <td className="px-3 py-3 align-top"><span className={`whitespace-nowrap rounded-full px-2 py-1 text-xs font-semibold ${statusClass(purchase.purchase_status)}`}>{PURCHASE_STATUS_LABELS[purchase.purchase_status] ?? label(purchase.purchase_status)}</span>
                  {payment?.payment_status && <div className="mt-1 text-[11px] text-neutral-500">Synchron: {label(payment.payment_status)}</div>}
                </td>
                <td className="px-3 py-3 align-top font-mono text-[11px] text-neutral-700">
                  <div title={payment?.synchron_purchase_token ?? ''}>sp {truncate(payment?.synchron_purchase_token)}</div>
                  <div title={payment?.stripe_checkout_session_id ?? ''}>cs {truncate(payment?.stripe_checkout_session_id)}</div>
                  <div title={payment?.stripe_payment_intent_id ?? ''}>pi {truncate(payment?.stripe_payment_intent_id)}</div>
                  {payment && <div className="text-neutral-400">{payment.source_system}</div>}
                </td>
                <td className="whitespace-nowrap px-3 py-3 align-top text-xs text-neutral-500">{utc(payment?.last_synced_at)}</td>
                <td className="px-3 py-3 align-top text-xs">
                  {purchase.needs_reconciliation && <span className="mb-1 block whitespace-nowrap rounded-full bg-amber-50 px-2 py-1 font-semibold text-amber-800">Needs reconciliation</span>}
                  {mismatch && <span className="block whitespace-nowrap rounded-full bg-red-50 px-2 py-1 font-semibold text-red-700">Mismatch — review</span>}
                  {!purchase.needs_reconciliation && !mismatch && '—'}
                </td>
                <td className="max-w-56 break-words px-3 py-3 align-top text-xs text-red-700">{lastError ? <span title={utc(lastError.created_at)}>{String(lastError.detail?.message ?? lastError.detail?.reason ?? lastError.detail?.operation ?? 'Synchron API error')}</span> : <span className="text-neutral-400">—</span>}</td>
                <td className="px-3 py-3 align-top"><PurchaseActions purchaseId={purchase.id} flagged={purchase.needs_reconciliation} /></td>
              </tr>)}
              {!rows.length && <tr><td colSpan={14} className="px-4 py-10 text-center text-neutral-500">No purchases match this window and filter.</td></tr>}
            </tbody>
          </table>
        </div>
      </main>
    </AppShell>
  )
}
