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

import TagLink from '@/components/TagLink'
import PrefetchLink from '@/components/PrefetchLink'
import PageTitle from '@/components/common/PageTitle'
import Pagination from '@/components/common/Pagination'
import { useDialogue } from '@/components/dialogues/DialogueProvider'
import MainArea from '@/components/layout/MainArea'
import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { clientAnimationTransition,
	 clientScrollBehaviour } from '@/lib/clientAnimation'
import { fetchPostChanges, updatePost } from '@/lib/posts'
import { postsKeys, tagsKeys } from '@/lib/queryKeys'
import { fetchTag } from '@/lib/tags'
import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings'
import { cn, dateString, originalCreatedAtString } from '@/lib/utils'

import type { FC, MouseEvent } from 'react'

import type { PostVersion } from '@/types'


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


const PostHistoryPage: FC = () => {
  const dialogue = useDialogue ()
  const behaviourSettings = useClientBehaviourSettings ()
  const animationMode = behaviourSettings.animation ?? 'normal'
  const layoutTransition = clientAnimationTransition (
      animationMode,
      { normal: { duration: .2, ease: 'easeOut' as const } },
  )

  const location = useLocation ()
  const query = new URLSearchParams (location.search)
  const id = query.get ('id')
  const tagId = query.get ('tag')
  const page = Number (query.get ('page') ?? 1)
  const limit = Number (query.get ('limit') ?? 20)

  // 投稿列の結合で使用
  let rowsCnt: number

  const tagQueryId = tagId ?? ''
  const { data: tag } = useQuery ({
      enabled:  Boolean (tagId),
      queryKey: tagsKeys.show (tagQueryId),
      queryFn:  () => fetchTag (tagQueryId) })

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

  const qc = useQueryClient ()

  const handleRevert = async (e: MouseEvent<HTMLAnchorElement>, change: PostVersion) => {
    e.preventDefault ()

    if (!(await dialogue.confirm ({
	title: '差戻の確認',
	description: `『${ change.title.current || change.url.current }』を版 ${
	    change.versionNo } に差戻します．\nよろしいですか?`,
	confirmText: '差戻' })))
      return

    try
    {
      const id = change.postId
      const title = change.title.current
      const tags =
	  change.tags
	  .filter (t => t.type !== 'removed')
	  .map (t => t.name)
	  .filter (t => t.slice (0, 5) !== 'nico:')
	  .join (' ')
      const parentPostIds =
	  (change.parentPosts ?? [])
	  .filter (p => p.type !== 'removed')
	  .map (p => p.id)
	  .join (' ')
      const duration =
	  change.videoMs.current == null
	  ? null
	  : String (change.videoMs.current / 1_000)
      const originalCreatedFrom = change.originalCreatedFrom.current
      const originalCreatedBefore = change.originalCreatedBefore.current
      await updatePost ({ id, title, tags, duration, parentPostIds,
			  originalCreatedFrom, originalCreatedBefore },
		        { force: true })

      qc.invalidateQueries ({ queryKey: postsKeys.root })
      qc.invalidateQueries ({ queryKey: tagsKeys.root })

      toast ({ description: '差戻しました．' })
    }
    catch
    {
      toast ({ description: '差戻に失敗……' })
    }
  }

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

  const layoutIds: string[] = []

  return (
      <MainArea>
	<Helmet>
	  <title>{`耕作履歴 | ${ SITE_TITLE }`}</title>
	</Helmet>

	<PageTitle>
	  耕作履歴
	  {id && <>: 投稿 {<PrefetchLink to={`/posts/${ id }`}>#{id}</PrefetchLink>}</>}
	  {tag && <>（<TagLink tag={tag} withWiki={false} withCount={false}/>）</>}
	</PageTitle>

	{loading ? 'Loading...' : (
	    <>
	      <div className="overflow-x-auto">
		<table className="w-full min-w-[1200px] table-fixed border-collapse">
		  <colgroup>
		    {/* 投稿 */}
		    <col className="w-64"/>
		    {/* 版 */}
		    <col className="w-40"/>
		    {/* タイトル */}
		    <col className="w-96"/>
		    {/* URL */}
		    <col className="w-96"/>
		    {/* タグ */}
		    <col className="w-[48rem]"/>
		    {/* TODO: 親投稿 */}
		    {/* <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">URL</th>
		      <th className="p-2 text-left">タグ</th>
		      {/* TODO: 親投稿の履歴 */}
		      {/* <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, i) => {
		      const withPost = i === 0 || change.postId !== changes[i - 1].postId
		      if (withPost)
			{
			  rowsCnt = 1
			  for (let j = i + 1;
			       (j < changes.length
				&& change.postId === changes[j].postId);
			       ++j)
			    ++rowsCnt
			}

		      let layoutId: string | undefined = `page-${ change.postId }`
		      if (layoutIds.includes (layoutId))
			layoutId = undefined
		      else
			layoutIds.push (layoutId)

		      return (
			  <tr key={`${ change.postId }.${ change.versionNo }`}
			      className={cn ('even:bg-gray-100 dark:even:bg-gray-700',
					     withPost && 'border-t')}>
			    {withPost && (
				<td className="align-top p-2 bg-white dark:bg-[#242424] border-r"
				    rowSpan={rowsCnt}>
				  <PrefetchLink to={`/posts/${ change.postId }`}>
				    <motion.div
					layoutId={animationMode === 'off' ? undefined : layoutId}
					transition={{ layout: layoutTransition }}>
				      <img src={change.thumbnail.current
						|| change.thumbnailBase.current
						|| undefined}
					   alt={change.title.current || change.url.current}
					   title={change.title.current || change.url.current || undefined}
					   className="w-40"/>
				    </motion.div>
				  </PrefetchLink>
				</td>)}
			    <td className="p-2">{change.postId}.{change.versionNo}</td>
			    <td className="p-2 break-all">{renderDiff (change.title)}</td>
			    <td className="p-2 break-all">{renderDiff (change.url)}</td>
			    <td className="p-2">
			      {change.tags.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>
			    {/* TODO: 親投稿の履歴 */}
			    {/* <td className="p-2">
			      {change.parentPosts.map ((pp, i) => (
				  pp.type === 'added'
				  ? (
				      <ins
					  key={i}
					  className="mr-2 text-green-600 dark:text-green-400">
					{pp.title}
				      </ins>)
				  : (
				      pp.type === 'removed'
				      ? (
					  <del
					      key={i}
					      className="mr-2 text-red-600 dark:text-red-400">
					    {pp.title}
					  </del>)
				      : (
					  <span key={i} className="mr-2">
					    {pp.title}
					  </span>))))}
			    </td> */}
			    <td className="p-2">
			      {change.versionNo === 1
			       ? originalCreatedAtString (change.originalCreatedFrom.current,
							  change.originalCreatedBefore.current)
			       : renderDiff ({
				  current: originalCreatedAtString (
					       change.originalCreatedFrom.current,
					       change.originalCreatedBefore.current),
				  prev: originalCreatedAtString (
					    change.originalCreatedFrom.prev,
					    change.originalCreatedBefore.prev) })}
			    </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 => await handleRevert (e, change)}>
				復元
			      </a>
			    </td>
			  </tr>)
		    })}
		  </tbody>
		</table>
	      </div>

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

export default PostHistoryPage
