import { h, type FunctionComponent } from 'preact'
import { useCallback, useEffect, useRef } from 'preact/hooks'
import { LocationProvider, Route, Router } from 'preact-iso'
import { get } from 'lowline'
import Head from './head.ts'
import Footer from './footer.tsx'
import Header from './header.tsx'
import ErrorPage from './error_page.tsx'
import routes from '../routes.ts'
import throttle from '../../shared/utils/throttle.ts'

import s from './app.module.scss'

type Props = {
  error?: Error
  title?: string
}

const scroll = () => {
  const offset = get(window.history, 'state.scrollTop')

  window.scrollTo(0, offset || 0)
}

const App: FunctionComponent<Props> = ({ error, title }) => {
  const loadRef = useRef<boolean>(false)

  useEffect(() => {
    history.scrollRestoration = 'manual'

    const remember = throttle(function remember() {
      if (loadRef.current) return

      window.history.replaceState(
        {
          ...window.history.state,
          scrollTop: window.scrollY,
        },
        '',
        null,
      )
    }, 100)

    addEventListener('scroll', remember)

    return () => removeEventListener('scroll', remember)
  }, [])

  const onLoadStart = useCallback(() => {
    loadRef.current = true
  }, [])

  const onLoadEnd = useCallback(() => {
    scroll()
    loadRef.current = false
  }, [])

  const onRouteChange = useCallback(() => {
    if (!loadRef.current) scroll()
  }, [])

  return (
    <LocationProvider>
      <div id='app' className={s.base}>
        <Head>
          <title>{title || 'Untitled'}</title>
        </Head>

        <Header routes={routes} />

        <main className={s.main}>
          {error ? (
            <ErrorPage error={error} />
          ) : (
            <Router onLoadStart={onLoadStart} onLoadEnd={onLoadEnd} onRouteChange={onRouteChange}>
              {routes.map((route) => (
                <Route key={route.path} path={route.path} component={route.component} />
              ))}
            </Router>
          )}
        </main>

        <Footer />
      </div>
    </LocationProvider>
  )
}

export default App
