import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useEffect } from 'react'
import { Helmet } from 'react-helmet-async'
import { useLocation } from 'react-router-dom'

import PrefetchLink from '@/components/PrefetchLink'
import PageTitle from '@/components/common/PageTitle'
import Pagination from '@/components/common/Pagination'
import MainArea from '@/components/layout/MainArea'
import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { CATEGORY_NAMES } from '@/consts'
import { apiPut } from '@/lib/api'
import { clientScrollBehaviour } from '@/lib/clientAnimation'
import { postsKeys, tagsKeys } from '@/lib/queryKeys'
import { fetchTagChanges } from '@/lib/tags'
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'
import { cn, dateString } from '@/lib/utils'

import type { FC } from 'react'


const renderDiff = (diff: { current: string | null; prev: string | null }) => (
    <>
      {diff.prev !== diff.current
       ? (
	  <>
	    <del className="text-red-600 dark:text-red-400">
	      {diff.prev && <>{diff.prev}<br/></>}
	    </del>
	    <ins className="text-green-600 dark:text-green-400">
	      {diff.current}
	    </ins>
	  </>)
       : diff.current}
    </>)


const tagStateLabel = (deprecatedAt: string | null) => deprecatedAt ? '廃止' : ''


const renderStateDiff = (diff: { current: string | null; prev: string | null }) =>
    renderDiff ({ current: tagStateLabel (diff.current),
		  prev: tagStateLabel (diff.prev) })


const TagHistoryPage: FC = () => {
  const behaviourSettings = useClientBehaviourSettings ()
  const animationMode = behaviourSettings.animation ?? 'normal'
  const location = useLocation ()
  const query = new URLSearchParams (location.search)
  const id = query.get ('id')
  const page = Number (query.get ('page') ?? 1)
  const limit = Number (query.get ('limit') ?? 20)

  const { data, isLoading: loading } = useQuery ({
      queryKey: tagsKeys.changes ({ ...(id && { id }), page, limit }),
      queryFn:  () => fetchTagChanges ({ ...(id && { id }), page, limit }) })
  const changes = data?.versions ?? []
  const totalPages = data ? Math.ceil (data.count / limit) : 0

  const qc = useQueryClient ()

  useEffect (() => {
    document.querySelector ('table')?.scrollIntoView ({
	behavior: clientScrollBehaviour (animationMode) })
  }, [animationMode, location.search])

  return (
      <MainArea>
	<Helmet>
	  <title>{`タグ定義変更履歴 | ${ SITE_TITLE }`}</title>
	</Helmet>

	<PageTitle>
	  タグ定義変更履歴
	  {id && <>: タグ {<PrefetchLink to={`/tags/${ id }`}>#{id}</PrefetchLink>}</>}
	</PageTitle>

	{loading ? 'Loading...' : (
	    <>
	      <div className="overflow-x-auto">
		<table className="w-full min-w-[1200px] table-fixed border-collapse">
		  <colgroup>
		    {/* 版 */}
		    <col className="w-40"/>
		    {/* 名称 */}
		    <col className="w-96"/>
		    {/* カテゴリ */}
		    <col className="w-96"/>
		    {/* 状態 */}
		    <col className="w-32"/>
		    {/* 別名 */}
		    <col className="w-[48rem]"/>
		    {/* 上位タグ */}
		    <col className="w-96"/>
		    {/* 更新日時 */}
		    <col className="w-64"/>
		    {/* (差戻ボタン) */}
		    <col className="w-20"/>
		  </colgroup>

		  <thead className="border-b-2 border-black dark:border-white">
		    <tr>
		      <th className="p-2 text-left">版</th>
		      <th className="p-2 text-left">名称</th>
		      <th className="p-2 text-left">カテゴリ</th>
		      <th className="p-2 text-left">状態</th>
		      <th className="p-2 text-left">別名</th>
		      <th className="p-2 text-left">上位タグ</th>
		      <th className="p-2 text-left">更新日時</th>
		      <th className="p-2"/>
		    </tr>
		  </thead>

		  <tbody>
		    {changes.map (change => (
			<tr key={`${ change.tagId }.${ change.versionNo }`}
			    className={cn ('even:bg-gray-100 dark:even:bg-gray-700')}>
			  <td className="p-2">{change.tagId}.{change.versionNo}</td>
			  <td className="p-2 break-all">{renderDiff (change.name)}</td>
			  <td className="p-2 break-all">
			    {renderDiff ({
				current: CATEGORY_NAMES[change.category.current],
				prev: (change.category.prev
				       && CATEGORY_NAMES[change.category.prev]) })}
			  </td>
			  <td className="p-2 break-all">
			    {renderStateDiff (change.deprecatedAt)}
			  </td>
			  <td className="p-2">
			    {change.aliases.map ((tag, i) => (
				tag.type === 'added'
				? (
				    <ins
					key={i}
					className="mr-2 text-green-600 dark:text-green-400">
				      {tag.name}
				    </ins>)
				: (
				    tag.type === 'removed'
				    ? (
					<del
					    key={i}
					    className="mr-2 text-red-600 dark:text-red-400">
					  {tag.name}
					</del>)
				    : (
					<span key={i} className="mr-2">
					  {tag.name}
					</span>))))}
			  </td>
			  <td className="p-2">
			    {change.parentTags.map ((tag, i) => (
				tag.type === 'added'
				? (
				    <ins
					key={i}
					className="mr-2 text-green-600 dark:text-green-400">
				      {tag.tag.name}
				    </ins>)
				: (
				    tag.type === 'removed'
				    ? (
					<del
					    key={i}
					    className="mr-2 text-red-600 dark:text-red-400">
					  {tag.tag.name}
					</del>)
				    : (
					<span key={i} className="mr-2">
					  {tag.tag.name}
					</span>))))}
			  </td>
			  <td className="p-2">
			    {change.createdByUser
			     ? (
				<PrefetchLink to={`/users/${ change.createdByUser.id }`}>
				  {change.createdByUser.name
				   || `名もなきニジラー（#${ change.createdByUser.id }）`}
				</PrefetchLink>)
			     : 'bot 操作'}
			    <br/>
			    {dateString (change.createdAt)}
			  </td>
			  <td className="p-2">
			    <a
				href="#"
				onClick={async e => {
				  e.preventDefault ()

				  if (!(confirm (
				      `タグ『${ change.name.current }』を版 ${
				      change.versionNo } に差戻します．\nよろしいですか?`)))
				    return

				  try
				  {
				    await apiPut (
					`/tags/${ change.tagId }`,
					{ name: change.name.current,
					  category: change.category.current,
					  deprecated: change.deprecatedAt.current ? '1' : '0',
					  aliases:
					      change.aliases
					      .filter (t => t.type !== 'removed')
					      .map (t => t.name)
					      .join (' '),
					  parent_tags:
					      change.parentTags
					      .filter (t => t.type !== 'removed')
					      .map (t => t.tag.name)
					      .join (' ') })

				    qc.invalidateQueries ({ queryKey: postsKeys.root })
				    qc.invalidateQueries ({ queryKey: tagsKeys.root })
				    toast ({ description: '差戻しました．' })
				  }
				  catch
				  {
				    toast ({ description: '差戻に失敗……' })
				  }
				}}>
			      復元
			    </a>
			  </td>
			</tr>))}
		  </tbody>
		</table>
	      </div>

	      <Pagination page={page} totalPages={totalPages}/>
	    </>)}
      </MainArea>)
}


export default TagHistoryPage
