"use client"

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react"
import { useServerInsertedHTML } from "next/navigation"

const STORAGE_KEY = "rl-theme"
const MEDIA_QUERY = "(prefers-color-scheme: dark)"
const THEMES = ["light", "dark", "system"] as const

type Theme = (typeof THEMES)[number]
type ResolvedTheme = "light" | "dark"

const THEME_INIT_SCRIPT = `(function(){try{var k="${STORAGE_KEY}",d="dark",e=document.documentElement,t=localStorage.getItem(k)||d,s=function(){return window.matchMedia("${MEDIA_QUERY}").matches?"dark":"light"}();if(t==="system")t=s;e.classList.remove("light","dark");e.classList.add(t);e.style.colorScheme=t}catch(n){}})()`

type ThemeContextValue = {
  theme: Theme | undefined
  setTheme: (theme: Theme | ((prev: Theme) => Theme)) => void
  resolvedTheme: ResolvedTheme | undefined
  systemTheme: ResolvedTheme | undefined
  themes: readonly Theme[]
}

const ThemeContext = createContext<ThemeContextValue | undefined>(undefined)

type ThemeProviderProps = {
  children: ReactNode
  defaultTheme?: Theme
  enableSystem?: boolean
  disableTransitionOnChange?: boolean
}

function readStoredTheme(defaultTheme: Theme, enableSystem: boolean): Theme {
  try {
    const stored = localStorage.getItem(STORAGE_KEY)
    if (stored === "light" || stored === "dark") return stored
    if (enableSystem && stored === "system") return stored
  } catch {
    // ignore
  }
  return defaultTheme
}

function resolveTheme(theme: Theme, systemTheme: ResolvedTheme): ResolvedTheme {
  return theme === "system" ? systemTheme : theme
}

function applyThemeClass(resolved: ResolvedTheme, disableTransitionOnChange: boolean) {
  const root = document.documentElement
  if (disableTransitionOnChange) {
    const style = document.createElement("style")
    style.appendChild(
      document.createTextNode(
        "*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}",
      ),
    )
    document.head.appendChild(style)
    window.getComputedStyle(document.body)
    setTimeout(() => {
      document.head.removeChild(style)
    }, 1)
  }
  root.classList.remove("light", "dark")
  root.classList.add(resolved)
  root.style.colorScheme = resolved
}

export function ThemeProvider({
  children,
  defaultTheme = "dark",
  enableSystem = true,
  disableTransitionOnChange = false,
}: ThemeProviderProps) {
  useServerInsertedHTML(() => (
    <script suppressHydrationWarning dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }} />
  ))

  const [theme, setThemeState] = useState<Theme>(defaultTheme)
  const [systemTheme, setSystemTheme] = useState<ResolvedTheme>("dark")
  const [ready, setReady] = useState(false)

  useEffect(() => {
    const media = window.matchMedia(MEDIA_QUERY)
    const onSystemChange = (event: MediaQueryListEvent) => {
      setSystemTheme(event.matches ? "dark" : "light")
    }

    setSystemTheme(media.matches ? "dark" : "light")
    media.addEventListener("change", onSystemChange)

    const stored = readStoredTheme(defaultTheme, enableSystem)
    setThemeState(stored)
    applyThemeClass(resolveTheme(stored, media.matches ? "dark" : "light"), false)
    setReady(true)

    const onStorage = (event: StorageEvent) => {
      if (event.key !== STORAGE_KEY || !event.newValue) return
      const next = event.newValue
      if (next !== "light" && next !== "dark" && next !== "system") return
      setThemeState(next)
    }
    window.addEventListener("storage", onStorage)

    return () => {
      media.removeEventListener("change", onSystemChange)
      window.removeEventListener("storage", onStorage)
    }
  }, [defaultTheme, enableSystem])

  useEffect(() => {
    if (!ready) return
    applyThemeClass(resolveTheme(theme, systemTheme), disableTransitionOnChange)
  }, [theme, systemTheme, ready, disableTransitionOnChange])

  const setTheme = useCallback((value: Theme | ((prev: Theme) => Theme)) => {
    setThemeState((prev) => {
      const next = typeof value === "function" ? value(prev) : value
      try {
        localStorage.setItem(STORAGE_KEY, next)
      } catch {
        // ignore
      }
      return next
    })
  }, [])

  const value = useMemo<ThemeContextValue>(
    () => ({
      theme: ready ? theme : undefined,
      setTheme,
      resolvedTheme: ready ? resolveTheme(theme, systemTheme) : undefined,
      systemTheme: ready ? systemTheme : undefined,
      themes: enableSystem ? THEMES : (["light", "dark"] as const),
    }),
    [ready, theme, setTheme, systemTheme, enableSystem],
  )

  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}

export function useTheme() {
  const value = useContext(ThemeContext)
  if (!value) {
    return {
      theme: undefined,
      setTheme: () => {},
      resolvedTheme: undefined,
      systemTheme: undefined,
      themes: [] as const,
    }
  }
  return value
}
