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

import PrefetchLink from '@/components/PrefetchLink'
import SortHeader from '@/components/SortHeader'
import TagLink from '@/components/TagLink'
import DateTimeField from '@/components/common/DateTimeField'
import Label from '@/components/common/Label'
import PageTitle from '@/components/common/PageTitle'
import Pagination from '@/components/common/Pagination'
import TagInput from '@/components/common/TagInput'
import MainArea from '@/components/layout/MainArea'
import { SITE_TITLE } from '@/config'
import { fetchPosts } from '@/lib/posts'
import { postsKeys } from '@/lib/queryKeys'
import { dateString, originalCreatedAtString } from '@/lib/utils'

import type { FC, FormEvent } from 'react'

import type { FetchPostsOrder,
	      FetchPostsOrderField,
	      FetchPostsParams } from '@/types'


const setIf = (qs: URLSearchParams, k: string, v: string | null) => {
  const t = v?.trim ()
  if (t)
    qs.set (k, t)
}


const PostSearchPage: FC = () => {
  const location = useLocation ()

  const navigate = useNavigate ()

  const query = useMemo (() => new URLSearchParams (location.search),
			 [location.search])

  const page = Number (query.get ('page') ?? 1)
  const limit = Number (query.get ('limit') ?? 20)

  const qURL = query.get ('url') ?? ''
  const qTitle = query.get ('title') ?? ''
  const qTags = query.get ('tags') ?? ''
  const qMatch: 'all' | 'any' = query.get ('match') === 'any' ? 'any' : 'all'
  const qOriginalCreatedFrom = query.get ('original_created_from') ?? ''
  const qOriginalCreatedTo = query.get ('original_created_to') ?? ''
  const qCreatedFrom = query.get ('created_from') ?? ''
  const qCreatedTo = query.get ('created_to') ?? ''
  const qUpdatedFrom = query.get ('updated_from') ?? ''
  const qUpdatedTo = query.get ('updated_to') ?? ''
  const order = (query.get ('order') || 'original_created_at:desc') as FetchPostsOrder

  const [createdFrom, setCreatedFrom] = useState<string | null> (null)
  const [createdTo, setCreatedTo] = useState<string | null> (null)
  const [matchType, setMatchType] = useState<'all' | 'any'> ('all')
  const [originalCreatedFrom, setOriginalCreatedFrom] = useState<string | null> (null)
  const [originalCreatedTo, setOriginalCreatedTo] = useState<string | null> (null)
  const [tagsStr, setTagsStr] = useState ('')
  const [title, setTitle] = useState ('')
  const [updatedFrom, setUpdatedFrom] = useState<string | null> (null)
  const [updatedTo, setUpdatedTo] = useState<string | null> (null)
  const [url, setURL] = useState ('')

  const keys: FetchPostsParams = {
      tags: qTags, match: qMatch, page, limit,
      url: qURL,
      title: qTitle,
      originalCreatedFrom: qOriginalCreatedFrom,
      originalCreatedTo: qOriginalCreatedTo,
      createdFrom: qCreatedFrom,
      createdTo: qCreatedTo,
      updatedFrom: qUpdatedFrom,
      updatedTo: qUpdatedTo,
      order }
  const { data, isLoading: loading } = useQuery ({
      queryKey: postsKeys.index (keys),
      queryFn: () => fetchPosts (keys) })
  const results = data?.posts ?? []
  const totalPages = data ? Math.ceil (data.count / limit) : 0

  useEffect (() => {
    setURL (qURL ?? '')
    setTitle (qTitle ?? '')
    setTagsStr (qTags ?? '')
    setMatchType (qMatch ?? 'all')
    setOriginalCreatedFrom (qOriginalCreatedFrom)
    setOriginalCreatedTo (qOriginalCreatedTo)
    setCreatedFrom (qCreatedFrom)
    setCreatedTo (qCreatedTo)
    setUpdatedFrom (qUpdatedFrom)
    setUpdatedTo (qUpdatedTo)

    document.querySelector ('table')?.scrollIntoView ({ behavior: 'smooth' })
  }, [location.search, qCreatedFrom, qCreatedTo, qMatch, qOriginalCreatedFrom,
      qOriginalCreatedTo, qTags, qTitle, qUpdatedFrom, qUpdatedTo, qURL])

  const search = async () => {
    const qs = new URLSearchParams ()
    setIf (qs, 'tags', tagsStr)
    setIf (qs, 'url', url)
    setIf (qs, 'title', title)
    setIf (qs, 'original_created_from', originalCreatedFrom)
    setIf (qs, 'original_created_to', originalCreatedTo)
    setIf (qs, 'created_from', createdFrom)
    setIf (qs, 'created_to', createdTo)
    setIf (qs, 'updated_from', updatedFrom)
    setIf (qs, 'updated_to', updatedTo)
    qs.set ('match', matchType)
    qs.set ('page', '1')
    qs.set ('order', order)
    navigate (`${ location.pathname }?${ qs.toString () }`)
  }

  const handleSearch = (e: FormEvent) => {
    e.preventDefault ()
    search ()
  }

  const defaultDirection = { title: 'asc',
			     url: 'asc',
			     original_created_at: 'desc',
			     created_at: 'desc',
			     updated_at: 'desc' } as const

  return (
      <MainArea>
	<Helmet>
	  <title>広場検索 | {SITE_TITLE}</title>
	</Helmet>

	<div className="max-w-xl">
	  <PageTitle>広場検索</PageTitle>

	  <form onSubmit={handleSearch} className="space-y-2">
	    {/* タイトル */}
	    <div>
	      <Label>タイトル</Label>
	      <input
		  type="text"
		  value={title}
		  onChange={e => setTitle (e.target.value)}
		  className="w-full border p-2 rounded"/>
	    </div>

	    {/* URL */}
	    <div>
	      <Label>URL</Label>
	      <input
		  type="text"
		  value={url}
		  onChange={e => setURL (e.target.value)}
		  className="w-full border p-2 rounded"/>
	    </div>

	    {/* タグ */}
	    <div>
	      <Label>タグ</Label>
	      <TagInput
		  value={tagsStr}
		  setValue={setTagsStr}/>
	      <fieldset className="w-full my-2">
		<label>検索区分：</label>
		<label className="mx-2">
		  <input
		      type="radio"
		      name="match-type"
		      checked={matchType === 'all'}
		      onChange={() => setMatchType ('all')}/>
		  AND
		</label>
		<label className="mx-2">
		  <input
		      type="radio"
		      name="match-type"
		      checked={matchType === 'any'}
		      onChange={() => setMatchType ('any')}/>
		  OR
		</label>
	      </fieldset>
	    </div>

	    {/* オリジナルの投稿日時 */}
	    <div>
	      <Label>オリジナルの投稿日時</Label>
	      <DateTimeField
		  value={originalCreatedFrom ?? undefined}
		  onChange={setOriginalCreatedFrom}/>
	      <span className="mx-1">〜</span>
	      <DateTimeField
		  value={originalCreatedTo ?? undefined}
		  onChange={setOriginalCreatedTo}/>
	    </div>

	    {/* 投稿日時 */}
	    <div>
	      <Label>投稿日時</Label>
	      <DateTimeField
		  value={createdFrom ?? undefined}
		  onChange={setCreatedFrom}/>
	      <span className="mx-1">〜</span>
	      <DateTimeField
		  value={createdTo ?? undefined}
		  onChange={setCreatedTo}/>
	    </div>

	    {/* 更新日時 */}
	    <div>
	      <Label>更新日時</Label>
	      <DateTimeField
		  value={updatedFrom ?? undefined}
		  onChange={setUpdatedFrom}/>
	      <span className="mx-1">〜</span>
	      <DateTimeField
		  value={updatedTo ?? undefined}
		  onChange={setUpdatedTo}/>
	    </div>

	    {/* 検索 */}
	    <div className="py-3">
	      <button
		  type="submit"
		  className="bg-blue-500 text-white px-4 py-2 rounded">
		検索
	      </button>
	    </div>
	  </form>
	</div>

	{loading ? 'Loading...' : (results.length > 0 ? (
	    <div className="mt-4">
	      <div className="overflow-x-auto">
		<table className="w-full min-w-[1200px] table-fixed border-collapse">
		  <colgroup>
		    <col className="w-14"/>
		    <col className="w-72"/>
		    <col className="w-80"/>
		    <col className="w-[24rem]"/>
		    <col className="w-60"/>
		    <col className="w-44"/>
		    <col className="w-44"/>
		  </colgroup>

		  <thead className="border-b-2 border-black dark:border-white">
		    <tr>
		      <th className="p-2 text-left whitespace-nowrap">投稿</th>
		      <th className="p-2 text-left whitespace-nowrap">
			<SortHeader<FetchPostsOrderField>
			    by="title"
			    label="タイトル"
			    currentOrder={order}
			    defaultDirection={defaultDirection}/>
		      </th>
		      <th className="p-2 text-left whitespace-nowrap">
			<SortHeader<FetchPostsOrderField>
			    by="url"
			    label="URL"
			    currentOrder={order}
			    defaultDirection={defaultDirection}/>
		      </th>
		      <th className="p-2 text-left whitespace-nowrap">タグ</th>
		      <th className="p-2 text-left whitespace-nowrap">
			<SortHeader<FetchPostsOrderField>
			    by="original_created_at"
			    label="オリジナルの投稿日時"
			    currentOrder={order}
			    defaultDirection={defaultDirection}/>
		      </th>
		      <th className="p-2 text-left whitespace-nowrap">
			<SortHeader<FetchPostsOrderField>
			    by="created_at"
			    label="投稿日時"
			    currentOrder={order}
			    defaultDirection={defaultDirection}/>
		      </th>
		      <th className="p-2 text-left whitespace-nowrap">
			<SortHeader<FetchPostsOrderField>
			    by="updated_at"
			    label="更新日時"
			    currentOrder={order}
			    defaultDirection={defaultDirection}/>
		      </th>
		    </tr>
		  </thead>
		  <tbody>
		    {results.map (row => (
			<tr key={row.id} className="even:bg-gray-100 dark:even:bg-gray-700">
			  <td className="p-2">
			    <PrefetchLink to={`/posts/${ row.id }`} title={row.title || undefined}>
			      <motion.div
				  layoutId={`page-${ row.id }`}
				  transition={{ type: 'spring',
						stiffness: 500,
						damping: 40,
						mass: .5 }}>
				<img src={row.thumbnail || row.thumbnailBase || undefined}
				     alt={row.title || row.url}
				     title={row.title || row.url || undefined}
				     className="w-8"/>
			      </motion.div>
			    </PrefetchLink>
			  </td>
			  <td className="p-2 truncate">
			    <PrefetchLink to={`/posts/${ row.id }`} title={row.title || undefined}>
			      {row.title}
			    </PrefetchLink>
			  </td>
			  <td className="p-2 truncate">
			    <a href={row.url}
			       title={row.url}
			       target="_blank"
			       rel="noopener noreferrer nofollow">
			      {row.url}
			    </a>
			  </td>
			  <td className="p-2">
			    {row.tags.map (t => (
				<span key={t.id} className="mr-2">
				  <TagLink tag={t} withWiki={false} withCount={false}/>
				</span>))}
			  </td>
			  <td className="p-2">
			    {originalCreatedAtString (row.originalCreatedFrom,
						      row.originalCreatedBefore)}
			  </td>
			  <td className="p-2">{dateString (row.createdAt)}</td>
			  <td className="p-2">{dateString (row.updatedAt)}</td>
			</tr>))}
		  </tbody>
		</table>
	      </div>

	      <Pagination page={page} totalPages={totalPages}/>
	    </div>) : '結果ないよ（笑）')}
      </MainArea>)
}

export default PostSearchPage
