import { QueryClient } from '@tanstack/react-query'
import { match } from 'path-to-regexp'

import { fetchPost, fetchPosts, fetchPostChanges } from '@/lib/posts'
import { postsKeys, wikiKeys } from '@/lib/queryKeys'
import { fetchWikiPageByTitle, fetchWikiPages } from '@/lib/wiki'

type Prefetcher = (qc: QueryClient, url: URL) => Promise<void>

const mPost = match<{ id: string }> ('/posts/:id')
const mWiki = match<{ title: string }> ('/wiki/:title')


const prefetchWikiPagesIndex: Prefetcher = async (qc, url) => {
  const title = url.searchParams.get ('title') ?? ''
  await qc.prefetchQuery ({
      queryKey: wikiKeys.index ({ title }),
      queryFn:  () => fetchWikiPages ({ title }) })
}


const prefetchWikiPageShow: Prefetcher = async (qc, url) => {
  const m = mWiki (url.pathname)
  if (!(m))
    return

  const version = url.searchParams.get ('version')
  const { title } = m.params
  await qc.prefetchQuery ({
      queryKey: wikiKeys.show (title, version ? { version } : { }),
      queryFn:  () => fetchWikiPageByTitle (title, version ? { version } : { }) })
}


const prefetchPostsIndex: Prefetcher = async (qc, url) => {
  const tags = url.searchParams.get ('tags') ?? ''
  const m = url.searchParams.get ('match') === 'any' ? 'any' : 'all'
  const page = Number (url.searchParams.get ('page') || 1)
  const limit = Number (url.searchParams.get ('limit') || 20)
  await qc.prefetchQuery ({
      queryKey: postsKeys.index ({ tags, match: m, page, limit }),
      queryFn:  () => fetchPosts ({ tags, match: m, page, limit }) })
}


const prefetchPostShow: Prefetcher = async (qc, url) => {
  const m = mPost (url.pathname)
  if (!(m))
    return

  const { id } = m.params
  await qc.prefetchQuery ({
      queryKey: postsKeys.show (id),
      queryFn:  () => fetchPost (id) })
}


const prefetchPostChanges: Prefetcher = async (qc, url) => {
  const id = url.searchParams.get ('id')
  const page = Number (url.searchParams.get ('page') || 1)
  const limit = Number (url.searchParams.get ('limit') || 20)
  await qc.prefetchQuery ({
      queryKey: postsKeys.changes ({ ...(id && { id }), page, limit }),
      queryFn:  () => fetchPostChanges ({ ...(id && { id }), page, limit }) })
}


export const routePrefetchers: { test: (u: URL) => boolean; run:  Prefetcher }[] = [
    { test: u => u.pathname === '/' || u.pathname === '/posts', run: prefetchPostsIndex },
    { test: u => (!(['/posts/new', '/posts/changes'].includes (u.pathname))
		  && Boolean (mPost (u.pathname))),
      run: prefetchPostShow },
    { test: u => u.pathname === '/posts/changes', run: prefetchPostChanges },
    { test: u => u.pathname === '/wiki', run: prefetchWikiPagesIndex },
    { test: u => (!(['/wiki/new', '/wiki/changes'].includes (u.pathname))
		  && Boolean (mWiki (u.pathname))),
      run: prefetchWikiPageShow },
    ]


export const prefetchForURL = async (qc: QueryClient, urlLike: string): Promise<void> => {
  const u = new URL (urlLike, location.origin)
  const jobs = routePrefetchers.filter (r => r.test (u)).map (r => r.run (qc, u))
  if (jobs.length === 0)
    return

  await Promise.all (jobs)
}
