import { Fragment, useEffect, useState } from 'react'

import TagLink from '@/components/TagLink'
import SidebarComponent from '@/components/layout/SidebarComponent'
import { apiGet } from '@/lib/api'

import type { FC, ReactNode } from 'react'

import type { Tag } from '@/types'

type TagWithDepth = Tag & {
    hasChildren:  boolean
    children:     TagWithDepth[] }


const setChildrenById = (
    tags:     TagWithDepth[],
    targetId: number,
    children: TagWithDepth[],
): TagWithDepth[] => (
    tags.map (tag => {
      if (tag.id === targetId)
	return { ...tag, children }

      if (tag.children.length === 0)
	return tag

      return { ...tag,
	       children: (setChildrenById (tag.children, targetId, children)
			  .filter (t => t.category !== 'meme' || t.hasChildren)) }
    }))


export default (() => {
  const [tags, setTags] = useState<TagWithDepth[]> ([])
  const [openTags, setOpenTags] = useState<Record<number, boolean>> ({ })
  const [tagFetchedFlags, setTagFetchedFlags] = useState<Record<number, boolean>> ({ })

  useEffect (() => {
    void (async () => {
      setTags ((await apiGet<TagWithDepth[]> ('/tags/with-depth'))
	       .filter (t => t.category !== 'meme' || t.hasChildren))
    }) ()
  }, [])

  const renderTags = (ts: TagWithDepth[], nestLevel = 0): ReactNode => (
      ts.map (t => (
	  <Fragment key={t.id}>
	    <li>
	      <div className="flex">
		<div className="flex-none w-4">
		  {t.hasChildren && (
		      <a
			  href="#"
			  onClick={async e => {
			    e.preventDefault ()
			    if (!(tagFetchedFlags[t.id]))
			      {
				try
				{
				  const data =
				      await apiGet<TagWithDepth[]> (
					  '/tags/with-depth', { params: { parent: String (t.id) } })
				  setTags (prev => setChildrenById (prev, t.id, data))
				  setTagFetchedFlags (prev => ({ ...prev, [t.id]: true }))
				}
				catch
				{
				  ;
				}
			      }
			    setOpenTags (prev => ({ ...prev, [t.id]: !(prev[t.id]) }))
			  }}>
			{openTags[t.id] ? <>&minus;</> : '+'}
		      </a>)}
		</div>
		<div className="flex-1 truncate">
		  <TagLink
		      tag={t}
		      nestLevel={nestLevel}
		      title={t.name}
		      withCount={false}
		      withWiki={false}
		      to={`/materials?tag=${ encodeURIComponent (t.name) }`}/>
		</div>
	      </div>
	    </li>
	    {openTags[t.id] && renderTags (t.children, nestLevel + 1)}
	  </Fragment>)))

  return (
      <SidebarComponent>
	<ul>
	  {renderTags (tags)}
	</ul>
      </SidebarComponent>)
}) satisfies FC
