import { AnimatePresence, motion } from 'framer-motion'
import { useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'

import TagLink from '@/components/TagLink'
import TagSearch from '@/components/TagSearch'
import SectionTitle from '@/components/common/SectionTitle'
import SidebarComponent from '@/components/layout/SidebarComponent'
import { CATEGORIES } from '@/consts'
import { apiGet } from '@/lib/api'
import { clientAnimationTransition } from '@/lib/clientAnimation'
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'

import type { FC, MouseEvent } from 'react'

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

type TagByCategory = Record<string, Tag[]>

type Props = { posts:     Post[]
	       onClick?:  (event: MouseEvent<HTMLElement>) => void }


const TagSidebar: FC<Props> = ({ posts, onClick }) => {
  const navigate = useNavigate ()
  const behaviourSettings = useClientBehaviourSettings ()
  const animationMode = behaviourSettings.animation ?? 'normal'
  const animationsOff = animationMode === 'off'
  const layoutTransition = clientAnimationTransition (
      animationMode,
      { normal: { duration: .2, ease: 'easeOut' as const } },
  )

  const [tagsVsbl, setTagsVsbl] = useState (false)
  const [tags, setTags] = useState<TagByCategory> ({ })

  const location = useLocation ()
  const query = new URLSearchParams (location.search)
  const tagsQuery = query.get ('tags') ?? ''
  const anyFlg = query.get ('match') === 'any'

  useEffect (() => {
    const tagsTmp: TagByCategory = { }
    let cnt = 0

  loop:
    for (const post of posts)
      {
	for (const tag of post.tags)
	  {
	    if (!(tag.category in tagsTmp))
	      tagsTmp[tag.category] = []

	    if (!(tagsTmp[tag.category].map (t => t.id).includes (tag.id)))
	      {
		tagsTmp[tag.category].push (tag)
		++cnt
		if (cnt >= 25)
		  break loop
	      }
	  }
      }

    for (const cat of Object.keys (tagsTmp))
      tagsTmp[cat].sort ((tagA, tagB) => tagA.name < tagB.name ? -1 : 1)

    setTags (tagsTmp)
  }, [posts])

  const TagBlock = (
      <>
	<SectionTitle>タグ</SectionTitle>
	<ul>
	  {CATEGORIES.flatMap (cat => cat in tags ? (
	      tags[cat].map (tag => (
		  <li key={tag.id} className="mb-1 min-w-0 max-w-full overflow-hidden">
		    {animationsOff
		     ? (
			 <div className="flex min-w-0 max-w-full items-baseline overflow-hidden">
			   <TagLink tag={tag} onClick={onClick}/>
			 </div>)
		     : (
			 <motion.div
			     className="flex min-w-0 max-w-full items-baseline overflow-hidden"
			     transition={{ layout: layoutTransition }}
			     layoutId={`tag-${ tag.id }`}>
			   <TagLink tag={tag} onClick={onClick}/>
			 </motion.div>)}
		  </li>))) : [])}
	</ul>
	<SectionTitle>関聯</SectionTitle>
	<a href="#"
	   onClick={ev => {
	     ev.preventDefault ()
	     void ((async () => {
	       try
	       {
		 const data = await apiGet<Post> ('/posts/random',
		     { params: { tags: tagsQuery.split (' ').filter (e => e !== '').join (' '),
				 match: (anyFlg ? 'any' : 'all') } })
		 navigate (`/posts/${ data.id }`)
	       }
	       catch
	       {
		 ;
	       }
	     }) ())
	   }}>
	  ランダム
	</a>
      </>)

  return (
      <SidebarComponent sidebarKey="posts-index-tags">
	<TagSearch/>

	<div className="hidden md:block mt-4">
	  {posts.length > 0 && TagBlock}
	</div>

	{animationsOff
	 ? (
	     tagsVsbl && (
		 <div className="md:hidden overflow-hidden">
		   {posts.length > 0 && TagBlock}
		 </div>))
	 : (
	     <AnimatePresence initial={false}>
	       {tagsVsbl && (
		   <motion.div
		       key="sptags"
		       className="md:hidden overflow-hidden"
		       initial={{ height: 0 }}
		       animate={{ height: 'auto' }}
		       exit={{ height: 0 }}
		       transition={layoutTransition}>
		     {posts.length > 0 && TagBlock}
		   </motion.div>)}
	     </AnimatePresence>)}

	<a href="#"
	   className="md:hidden block my-2 text-center text-sm
		      text-gray-500 hover:text-gray-400
		      dark:text-gray-300 dark:hover:text-gray-100"
	   onClick={ev => {
	     ev.preventDefault ()
	     setTagsVsbl (v => !(v))
	   }}>
	  {tagsVsbl ? '▲▲▲ タグ一覧を閉じる ▲▲▲' : '▼▼▼ タグ一覧を表示 ▼▼▼'}
	</a>
      </SidebarComponent>)
}

export default TagSidebar
