'use client'

import { useCallback, useMemo, useState, useSyncExternalStore } from 'react'
import { toast } from 'sonner'
import { Button } from '@/components/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { stateName } from '@/lib/domain/states'
import { PAYG } from '@/lib/demo/credits'

/**
 * Buying a route — prepaid credits vs. a shopping cart (2026-09-07, Task 69).
 *
 * Nash: "if I have an active balance of prepaid express routes… there's no
 * need for a shopping cart. I should have a button to [get] the express route,
 * and it should show me there that I have 15 available. When I buy one, it's
 * gonna go drop to 14, to 13."
 *
 * Nash: "just a one click with an alert, it's not enough, because this is a
 * money transaction. If I need to pay for it, it should go into a shopping
 * cart, and then I should pay for the items."
 *
 * ONE implementation for the desktop workspace permit card and the driver's
 * Active Trip route row — "the same flow, the same logic".
 */

export interface RouteCredits {
  planName: string
  included: number
  used: number
  remaining: number
}

export type RouteType = 'express' | 'extended'

export interface CartItem {
  stateCode: string
  routeType: RouteType
}

/** Whole cents so totals never drift (Express $1.99, Extended $10). */
const PRICE_CENTS: Record<RouteType, number> = { express: 199, extended: 1000 }
export const PRICE_LABEL: Record<RouteType, string> = {
  express: PAYG.express.price,
  extended: PAYG.extended.price,
}
const dollars = (cents: number) => `$${(cents / 100).toFixed(2)}`

/* ---------------- Cart: per user, per trip ---------------- */

const CART_EVENT = 'hha-route-cart'
const cartKey = (tripId: string, userId: string) => `hha-route-cart:${tripId}:${userId}`

function readCart(key: string): CartItem[] {
  try {
    const raw = localStorage.getItem(key)
    const parsed = raw ? JSON.parse(raw) : []
    return Array.isArray(parsed) ? parsed : []
  } catch {
    return []
  }
}

function writeCart(key: string, items: CartItem[]) {
  try {
    if (items.length === 0) localStorage.removeItem(key)
    else localStorage.setItem(key, JSON.stringify(items))
  } catch {
    // storage unavailable — the cart still works for this page
  }
  window.dispatchEvent(new CustomEvent(CART_EVENT, { detail: key }))
}

export interface RouteCart {
  items: CartItem[]
  has: (stateCode: string) => boolean
  add: (item: CartItem) => void
  remove: (stateCode: string) => void
  clear: () => void
  totalCents: number
}

/**
 * The cart belongs to one user on one trip (routes belong to a trip; a cart
 * shared across trips would mix orders for different loads). It survives a
 * reload and stays in sync between the button and the cart bar on the page.
 */
export function useRouteCart(tripId: string, userId: string): RouteCart {
  const key = cartKey(tripId, userId)

  // localStorage is the source of truth; the cart bar and every purchase
  // button on the page subscribe to the same key, so they never disagree.
  const subscribe = useCallback(
    (onChange: () => void) => {
      const onEvent = (e: Event) => {
        if ((e as CustomEvent).detail === key) onChange()
      }
      const onStorage = (e: StorageEvent) => {
        if (e.key === key) onChange()
      }
      window.addEventListener(CART_EVENT, onEvent)
      window.addEventListener('storage', onStorage)
      return () => {
        window.removeEventListener(CART_EVENT, onEvent)
        window.removeEventListener('storage', onStorage)
      }
    },
    [key],
  )
  const getSnapshot = useCallback(() => {
    try {
      return localStorage.getItem(key) ?? ''
    } catch {
      return ''
    }
  }, [key])
  const raw = useSyncExternalStore(subscribe, getSnapshot, () => '')
  const items = useMemo<CartItem[]>(() => {
    if (!raw) return []
    try {
      const parsed = JSON.parse(raw)
      return Array.isArray(parsed) ? parsed : []
    } catch {
      return []
    }
  }, [raw])

  const add = useCallback(
    (item: CartItem) => {
      const current = readCart(key)
      if (current.some((i) => i.stateCode === item.stateCode)) return
      writeCart(key, [...current, item])
    },
    [key],
  )
  const remove = useCallback(
    (stateCode: string) => writeCart(key, readCart(key).filter((i) => i.stateCode !== stateCode)),
    [key],
  )
  const clear = useCallback(() => writeCart(key, []), [key])

  return {
    items,
    has: (stateCode) => items.some((i) => i.stateCode === stateCode),
    add,
    remove,
    clear,
    totalCents: items.reduce((sum, i) => sum + PRICE_CENTS[i.routeType], 0),
  }
}

/* ---------------- The button on a permit / state ---------------- */

async function orderRoute(
  tripId: string,
  stateCode: string,
  routeType: RouteType | undefined,
  paidWith: 'credit' | 'card',
): Promise<string | null> {
  const res = await fetch(`/api/trips/${tripId}/requests`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      type: 'route_request',
      state_code: stateCode,
      notes: '',
      paid_with: paidWith,
      ...(routeType ? { route_type: routeType } : {}),
    }),
  })
  const json = await res.json().catch(() => ({}))
  return res.ok ? null : (json.error ?? 'Could not order the route')
}

const EXPLAINER =
  "You're buying the route for this permit — a Google Maps route (in parts where the state needs it), a GPX file for the truck GPS, and a Hummer GPS link. Our trusted partner Synchron Permits reads the permit and builds the map with a pin for every exit, so it's easy to see which way the truck goes. One purchase unlocks it for everyone on this trip."

export function RoutePurchaseControl({
  tripId,
  stateCode,
  routeType,
  credits,
  cart,
  onOrdered,
  variant = 'workspace',
}: {
  tripId: string
  stateCode: string
  /** Express / Extended is assigned by the backend; undefined = not known yet. */
  routeType?: RouteType
  credits: RouteCredits
  cart: RouteCart
  onOrdered: () => void
  variant?: 'workspace' | 'driver'
}) {
  const [confirming, setConfirming] = useState(false)
  const [pending, setPending] = useState(false)
  // Express is the standard product; Extended is the exception Synchron
  // assigns when a state needs it. A route whose type is not known yet is
  // priced as Express until the backend says otherwise.
  const effectiveType: RouteType = routeType ?? 'express'
  // Prepaid credits cover Express Routes only (strategy doc; unchanged).
  const creditsApply = effectiveType === 'express' && credits.remaining > 0

  const btn =
    variant === 'driver'
      ? 'rounded-lg bg-navy-900 px-3 py-1.5 text-[11px] font-bold text-white hover:bg-navy-800 disabled:opacity-60'
      : 'rounded-md bg-[#f5a623] px-2 py-0.5 text-[11px] font-bold text-[#0f1b2d] transition hover:bg-[#d98b06] disabled:opacity-60'

  async function spendCredit() {
    setPending(true)
    try {
      const error = await orderRoute(tripId, stateCode, effectiveType, 'credit')
      if (error) {
        toast.error(error)
        return
      }
      const left = Math.max(credits.remaining - 1, 0)
      toast.success(
        `Route ordered for ${stateName(stateCode)} — 1 Express Route credit used, ${left} left. It unlocks for everyone on this trip.`,
      )
      setConfirming(false)
      onOrdered()
    } finally {
      setPending(false)
    }
  }

  if (creditsApply) {
    return (
      <span className="group/buy relative inline-block">
        <button
          type="button"
          onClick={() => setConfirming((c) => !c)}
          disabled={pending}
          className={btn}
          title={EXPLAINER}
        >
          Use 1 Express Route credit · {credits.remaining} left
        </button>
        {/* Light inline confirm — a mis-tap on a phone must never silently
            burn a prepaid credit; still two taps, no cart, balance visible at
            the moment of spending. */}
        {confirming && (
          <span
            role="dialog"
            className="absolute right-0 top-full z-30 mt-1.5 w-64 rounded-xl border border-line bg-white p-3 text-left text-[11px] font-normal leading-relaxed text-ink shadow-xl"
          >
            <span className="block font-bold">{stateName(stateCode)} Express Route</span>
            <span className="mt-0.5 block text-ok">
              ✓ Covered by your plan ({credits.remaining} of {credits.included} Express Routes left)
            </span>
            <span className="mt-2 flex gap-2">
              <button
                type="button"
                onClick={spendCredit}
                disabled={pending}
                className="rounded-lg bg-navy-900 px-3 py-1.5 font-bold text-white disabled:opacity-60"
              >
                {pending ? '…' : 'Use 1 credit'}
              </button>
              <button
                type="button"
                onClick={() => setConfirming(false)}
                disabled={pending}
                className="rounded-lg border border-line px-3 py-1.5 font-bold text-slate-body"
              >
                Cancel
              </button>
            </span>
          </span>
        )}
      </span>
    )
  }

  if (cart.has(stateCode)) {
    return (
      <span
        className={`inline-block rounded-md px-2 py-1 text-[10px] font-bold text-ok ring-1 ring-inset ring-ok/30 ${
          variant === 'driver' ? 'bg-ok-bg' : 'bg-green-50'
        }`}
        title="In your cart — use Review & pay to order it"
      >
        🛒 In cart
      </span>
    )
  }

  return (
    <button
      type="button"
      onClick={() => {
        cart.add({ stateCode, routeType: effectiveType })
        toast.success(`${stateName(stateCode)} route added to your cart`)
      }}
      className={btn}
      title={`${EXPLAINER}${
        effectiveType === 'extended'
          ? ' This state requires Extended Route processing; included Express Route credits cannot be used for it.'
          : credits.included > 0
            ? ' You have used all included Express Route credits this month.'
            : ''
      }`}
    >
      Add to cart · {PRICE_LABEL[effectiveType]}
    </button>
  )
}

/* ---------------- The active cart on the page ---------------- */

export function CartBar({
  tripId,
  cart,
  onPaid,
  variant = 'workspace',
}: {
  tripId: string
  cart: RouteCart
  onPaid: () => void
  variant?: 'workspace' | 'driver'
}) {
  const [open, setOpen] = useState(false)
  const [paying, setPaying] = useState(false)
  if (cart.items.length === 0) return null

  async function pay() {
    setPaying(true)
    try {
      const failed: string[] = []
      for (const item of cart.items) {
        const error = await orderRoute(tripId, item.stateCode, item.routeType, 'card')
        if (error) failed.push(stateName(item.stateCode))
        else cart.remove(item.stateCode)
      }
      if (failed.length > 0) {
        toast.error(`Could not order: ${failed.join(', ')} — they stay in your cart.`)
      } else {
        toast.success(
          `Ordered ${cart.items.length} route${cart.items.length === 1 ? '' : 's'} — they unlock for everyone on this trip.`,
        )
        setOpen(false)
      }
      onPaid()
    } finally {
      setPaying(false)
    }
  }

  const n = cart.items.length
  return (
    <>
      <div
        className={
          variant === 'driver'
            ? 'flex items-center justify-between gap-2 rounded-2xl border border-amber-brand/60 bg-white p-3 text-xs shadow-sm'
            : 'flex items-center justify-between gap-2 border-b bg-amber-50 px-4 py-2.5 text-xs'
        }
      >
        <p className="min-w-0 truncate font-semibold text-ink">
          🛒 {n} route{n === 1 ? '' : 's'} in cart · {dollars(cart.totalCents)}
        </p>
        <span className="flex shrink-0 items-center gap-1.5">
          <Button size="sm" onClick={() => setOpen(true)} className="h-7 bg-[#0f1b2d] text-[11px] font-bold">
            Review &amp; pay
          </Button>
          <Button size="sm" variant="ghost" onClick={cart.clear} className="h-7 text-[11px]">
            Clear
          </Button>
        </span>
      </div>

      <Dialog open={open} onOpenChange={(o) => !paying && setOpen(o)}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Review your routes ({n})</DialogTitle>
          </DialogHeader>
          <ul className="divide-y text-sm">
            {cart.items.map((item) => (
              <li key={item.stateCode} className="flex items-center justify-between gap-2 py-2">
                <span className="min-w-0">
                  <span className="font-semibold">{stateName(item.stateCode)}</span>
                  <span className="ml-1.5 text-xs capitalize text-neutral-500">{item.routeType} route</span>
                </span>
                <span className="flex shrink-0 items-center gap-2">
                  <span className="font-mono text-xs">{dollars(PRICE_CENTS[item.routeType])}</span>
                  <button
                    type="button"
                    onClick={() => cart.remove(item.stateCode)}
                    disabled={paying}
                    className="text-xs text-neutral-400 hover:text-red-600"
                    title="Remove from cart"
                  >
                    ✕
                  </button>
                </span>
              </li>
            ))}
          </ul>
          <p className="flex items-center justify-between border-t pt-3 text-sm font-bold">
            <span>Total — one payment</span>
            <span className="font-mono">{dollars(cart.totalCents)}</span>
          </p>
          <p className="rounded-lg bg-amber-50 p-2.5 text-[11px] leading-relaxed text-amber-900">
            Card payment connects later — no card is charged in this pilot build. Paying records the
            order for every route above with our trusted partner Synchron Permits, and each route
            unlocks for everyone on this trip.
          </p>
          <div className="flex justify-end gap-2">
            <Button variant="ghost" onClick={() => setOpen(false)} disabled={paying}>
              Cancel
            </Button>
            <Button
              onClick={pay}
              disabled={paying}
              className="bg-[#f5a623] font-bold text-[#0f1b2d] hover:bg-[#d98b06]"
            >
              {paying ? 'Ordering…' : `Pay ${dollars(cart.totalCents)}`}
            </Button>
          </div>
        </DialogContent>
      </Dialog>
    </>
  )
}
