import axios from 'axios'
import toCamel from 'camelcase-keys'
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { Link, useLocation, useNavigationType } from 'react-router-dom'

import PostList from '@/components/PostList'
import TagSidebar from '@/components/TagSidebar'
import WikiBody from '@/components/WikiBody'
import TabGroup, { Tab } from '@/components/common/TabGroup'
import MainArea from '@/components/layout/MainArea'
import { API_BASE_URL, SITE_TITLE } from '@/config'

import type { Post, WikiPage } from '@/types'


export default () => {
  const navigationType = useNavigationType ()

  const containerRef = useRef<HTMLDivElement | null> (null)
  const loaderRef = useRef<HTMLDivElement | null> (null)

  const [cursor, setCursor] = useState ('')
  const [loading, setLoading] = useState (false)
  const [posts, setPosts] = useState<Post[]> ([])
  const [wikiPage, setWikiPage] = useState<WikiPage | null> (null)

  const loadMore = async (withCursor: boolean) => {
    setLoading (true)

    const res = await axios.get (`${ API_BASE_URL }/posts`, {
	params: { tags:   tags.join (' '),
		  match:  anyFlg ? 'any' : 'all',
		  limit:  '20',
		  ...(withCursor && { cursor }) } })
    const data = toCamel (res.data as any, { deep: true }) as { posts:      Post[]
								nextCursor: string }
    setPosts (posts => (
	[...((new Map ([...(withCursor ? posts : []), ...data.posts]
		       .map (post => [post.id, post])))
	     .values ())]))
    setCursor (data.nextCursor)

    setLoading (false)
  }

  const location = useLocation ()
  const query = new URLSearchParams (location.search)
  const tagsQuery = query.get ('tags') ?? ''
  const anyFlg = query.get ('match') === 'any'
  const tags = tagsQuery.split (' ').filter (e => e !== '')

  useEffect(() => {
    const observer = new IntersectionObserver (entries => {
      if (entries[0].isIntersecting && !(loading) && cursor)
	loadMore (true)
    }, { threshold: 1 })

    const target = loaderRef.current
    target && observer.observe (target)

    return () => {
      target && observer.unobserve (target)
    }
  }, [loaderRef, loading])

  useLayoutEffect (() => {
    const savedState = sessionStorage.getItem (`posts:${ tagsQuery }`)
    if (savedState && navigationType === 'POP')
      {
	const { posts, cursor, scroll } = JSON.parse (savedState)
	setPosts (posts)
	setCursor (cursor)

	if (containerRef.current)
	  containerRef.current.scrollTop = scroll

	loadMore (true)
      }
    else
      {
	setPosts ([])
	loadMore (false)
      }

    setWikiPage (null)
    if (tags.length === 1)
      {
	void (async () => {
	  try
	  {
	    const tagName = tags[0]
	    const res = await axios.get (`${ API_BASE_URL }/wiki/title/${ tagName }`)
	    setWikiPage (toCamel (res.data as any, { deep: true }) as WikiPage)
	  }
	  catch
	  {
	    ;
	  }
	}) ()
      }
  }, [location.search])

  return (
      <div className="md:flex md:flex-1" ref={containerRef}>
	<Helmet>
	  <title>
	    {tags.length
	     ? `${ tags.join (anyFlg ? ' or ' : ' and ') } | ${ SITE_TITLE }`
	     : `${ SITE_TITLE }　〜 ぼざろクリーチャーシリーズ綜合リンク集サイト`}
	  </title>
	</Helmet>

	<TagSidebar posts={posts.slice (0, 20)}/>

	<MainArea>
	  <TabGroup>
	    <Tab name="広場">
	      {posts.length
	       ? (
		  <PostList posts={posts} onClick={() => {
		    const statesToSave = {
			posts, cursor,
			scroll: containerRef.current?.scrollTop ?? 0 }
		    sessionStorage.setItem (`posts:${ tagsQuery }`,
					    JSON.stringify (statesToSave))
		  }}/>)
	       : !(loading) && '広場には何もありませんよ．'}
	      {loading && 'Loading...'}
	      <div ref={loaderRef} className="h-12"/>
	    </Tab>
	    {tags.length === 1 && (
		<Tab name="Wiki">
		  <WikiBody title={tags[0]} body={wikiPage?.body}/>
		  <div className="my-2">
		    <Link to={`/wiki/${ encodeURIComponent (tags[0]) }`}>
		      Wiki を見る
		    </Link>
		  </div>
		</Tab>)}
	  </TabGroup>
	</MainArea>
      </div>)
}
