import axios from 'axios'
import toCamel from 'camelcase-keys'
import { useEffect, useState } from 'react'
import ReactMarkdown from 'react-markdown'
import { Link } from 'react-router-dom'
import remarkGFM from 'remark-gfm'

import SectionTitle from '@/components/common/SectionTitle'
import SubsectionTitle from '@/components/common/SubsectionTitle'
import { API_BASE_URL } from '@/config'

import type { FC } from 'react'
import type { Components } from 'react-markdown'

import type { WikiPage } from '@/types'

type Props = { title: string
	       body?: string }

const mdComponents = { h1:  ({ children }) => <SectionTitle>{children}</SectionTitle>,
		       h2:  ({ children }) => <SubsectionTitle>{children}</SubsectionTitle>,
		       ol:  ({ children }) => <ol className="list-decimal pl-6">{children}</ol>,
		       ul:  ({ children }) => <ul className="list-disc pl-6">{children}</ul>,
		       a:   (({ href, children }) => (
				['/', '.'].some (e => href?.startsWith (e))
			        ? <Link to={href!}>{children}</Link>
			        : (
				    <a href={href}
				       target="_blank"
				       rel="noopener noreferrer">
				      {children}
				    </a>))) } as const satisfies Components


export default (({ title, body }: Props) => {
  const [pageNames, setPageNames] = useState<string[]> ([])
  const [realBody, setRealBody] = useState<string> ('')

  useEffect (() => {
    if (!(body))
      return

    void (async () => {
      try
      {
	const res = await axios.get (`${ API_BASE_URL }/wiki`)
	const data = toCamel (res.data as any, { deep: true }) as WikiPage[]
	setPageNames (data.map (page => page.title).sort ((a, b) => b.length - a.length))
      }
      catch
      {
	setPageNames ([])
      }
    }) ()
  }, [])

  useEffect (() => {
    setRealBody ('')
  }, [body])

  useEffect (() => {
    if (!(body))
      return

    const matchIndices = (target: string, keyword: string) => {
      const indices: number[] = []
      let pos = 0
      let idx
      while ((idx = target.indexOf (keyword, pos)) >= 0)
	{
	  indices.push (idx)
	  pos = idx + keyword.length
	}

      return indices
    }

    const linkIndices = (text: string, names: string[]): [string, [number, number]][] => {
      const result: [string, [number, number]][] = []

      names.forEach (name => {
	matchIndices (text, name).forEach (idx => {
	  const start = idx
	  const end = idx + name.length
	  const overlaps = result.some (([, [st, ed]]) => start < ed && end > st)
	  if (!(overlaps))
	    result.push ([name, [start, end]])
	})
      })

      return result.sort (([, [a]], [, [b]]) => b - a)
    }

    setRealBody (
	linkIndices (body, pageNames).reduce ((acc, [name, [start, end]]) => (
	    acc.slice (0, start)
	    + `[${ name }](/wiki/${ encodeURIComponent (name) })`
	    + acc.slice (end)), body))
  }, [body, pageNames])

  return (
      <ReactMarkdown components={mdComponents} remarkPlugins={[remarkGFM]}>
	{realBody || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`}
      </ReactMarkdown>)
}) satisfies FC<Props>
