import { useEffect, useState } from 'react'

/**
 * deviceTier
 * ---------------------------------------------------------------------------
 * Single source of truth for "how much 3D can this device afford". Every perf
 * decision in the experience (Canvas dpr/shadows, which meshes to draw, whether
 * to run Lenis, scroll length, post-fx) keys off this one classifier so the
 * desktop / tablet / mobile behaviour stays consistent and is tuned in one place.
 *
 *   'desktop' — full scene, soft shadows, environment, Lenis smooth-scroll
 *   'tablet'  — reduced foliage, hard shadows, environment, native scroll
 *   'mobile'  — truck + road + warehouse shell, no shadows, native scroll
 *
 * `fallback` is the escape hatch: reduced-motion users, no-WebGL contexts, and
 * very low-memory devices get a static poster instead of a live canvas.
 *
 * All detection is guarded for SSR (Next static export prerenders this module),
 * where it resolves to 'desktop' with no capability flags — the real value is
 * computed on the client after mount.
 */

function detectWebGL() {
  if (typeof document === 'undefined') return true
  try {
    const canvas = document.createElement('canvas')
    return !!(
      window.WebGLRenderingContext &&
      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
    )
  } catch {
    return false
  }
}

export function getDeviceCaps() {
  // SSR / prerender: assume the capable path; the client re-evaluates on mount.
  if (typeof window === 'undefined') {
    return { tier: 'desktop', isTouch: false, reducedMotion: false, fallback: false, lowMemory: false }
  }

  const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
  const coarse = window.matchMedia('(pointer: coarse)').matches
  const isTouch = coarse || navigator.maxTouchPoints > 0
  const width = window.innerWidth
  // navigator.deviceMemory is Chromium-only; treat "unknown" as plenty.
  const mem = typeof navigator.deviceMemory === 'number' ? navigator.deviceMemory : 8
  const cores = navigator.hardwareConcurrency || 8
  const hasWebGL = detectWebGL()

  const lowMemory = mem <= 4

  let tier
  if (!isTouch && width >= 1024) {
    tier = 'desktop'
  } else if (width >= 768 && width <= 1366) {
    tier = 'tablet'
  } else if (isTouch && width < 768) {
    tier = 'mobile'
  } else {
    // Small non-touch window, or anything else ambiguous → treat as tablet.
    tier = width < 768 ? 'mobile' : 'tablet'
  }

  // Hard downgrade for genuinely weak hardware regardless of width.
  if ((mem <= 2 || cores <= 2) && tier !== 'mobile') tier = 'mobile'

  // Static poster instead of a live scene when the device can't (or shouldn't)
  // run it: reduced-motion preference, no WebGL, or extremely low memory.
  const fallback = reducedMotion || !hasWebGL || mem <= 1

  return { tier, isTouch, reducedMotion, fallback, lowMemory }
}

/**
 * Resolve device caps once on mount. We intentionally do NOT update on resize:
 * the tier drives Canvas creation (dpr/shadows), and remounting the WebGL
 * context on every resize/orientation tweak would be far more expensive than
 * the marginal benefit of re-tiering mid-session. CameraRig already handles
 * aspect-ratio changes at runtime, so rotation still looks correct.
 *
 * Returns `null` until mounted so callers can hold off creating the Canvas
 * until the real (client) tier is known — avoids an SSR 'desktop' Canvas
 * flashing on a phone.
 */
export function useDeviceCaps() {
  const [caps, setCaps] = useState(null)
  useEffect(() => {
    setCaps(getDeviceCaps())
  }, [])
  return caps
}
