import axios from 'axios'
import crypto from 'crypto'
import fs from 'fs'
import path from 'path'

const formatDate = (date = new Date) => {
  const year = date.getFullYear ()
  const month = (date.getMonth () + 1).toString ().padStart (2, '0')
  const day = date.getDate ().toString ().padStart (2, '0')

  return `${ year }-${ month }-${ day }`
}

const SITE_TITLE = 'ぼざクリ タグ広場'
const DOMAIN = 'https://hub.nizika.monster'
const API_BASE_URL = 'https://hub.nizika.monster/api'

const fetchPosts = async tagName => (await axios.get (`${ API_BASE_URL }/posts`,
    { params: { ...(tagName && { tags:  tagName,
                                 match: 'all',
                                 limit: '20' }) } })).data.posts

const fetchTags = async () => (await axios.get (`${ API_BASE_URL }/tags`)).data.tags
const fetchTagNames = async () => (await fetchTags ()).map (tag => tag.name)

const fetchWikiPages = async () => (await axios.get (`${ API_BASE_URL }/wiki`)).data
const fetchWikiTitles = async () => (await fetchWikiPages ()).map (page => page.title)

const createPostListOutlet = async tagName => `
    <main class="flex-1 overflow-y-auto p-4">
      <div class="mt-4">
        <div class="flex gap-4"><a href="#" class="font-bold">広場</a></div>
        <div class="mt-2">
          <div class="flex flex-wrap gap-6 p-4">
            ${ (await fetchPosts (tagName)).slice (0, 20).map (post => `
                <a class="w-40 h-40 overflow-hidden rounded-lg shadow-md hover:shadow-lg"
                   href="/posts/${ post.id }">
                  <img alt="${ post.title }"
                       title="${ post.title }"
                       loading="eager"
                       fetchpriority="high"
                       decoding="async"
                       class="object-none w-full h-full"
                       src="${ post.thumbnail }" />
                </a>`).join ('') }
          </div>
        </div>
      </div>
    </main>`

const createPostDetailOutlet = post => `
    <div class="md:flex md:flex-1">
      <div>
        <div>
          ${ ['deerjikist', 'meme', 'character', 'general', 'material', 'meta', 'nico']
             .map (cat => '<ul>' + post.tags.filter (tag => tag.category === cat).map (tag => `
              <li>
                <span>
                  <a href="/wiki/${ encodeURIComponent (tag.name) }">?</a>
                </span>
                <a href="/posts?${ new URLSearchParams ({ tags: tag.name }) }">
                  ${ tag.name }
                </a>
                <span>${ tag['post_count'] }</span>
              </li>`).join ('') + '</ul>').join ('') }
        </div>
      </div>
      <main class="flex-1 overflow-y-auto p-4">
        <img src="${ post.thumbnail }" alt="${ post.url }" />
      </main>
    </div>`

const posts = (await fetchPosts ()).map (post => [
    `/posts/${ post.id }`,
    `${ post.title || post.url } | ${ SITE_TITLE }`,
    createPostDetailOutlet (post)])

const tags = []
for (const tag of await fetchTags ())
  {
    tags.push ([`/posts?${ new URLSearchParams ({ tags: tag.name }) }`,
                `${ tag.name } | ${ SITE_TITLE }`,
                await createPostListOutlet (tag.name)])
  }

const wikiPages = (await fetchWikiPages ()).map (page => [
    `/wiki/${ encodeURIComponent (page.title) }`,
    `${ page.title } Wiki | ${ SITE_TITLE }`])

const routes = [
    ['/', `${ SITE_TITLE }　〜 ぼざろクリーチャーシリーズ綜合リンク集`,
     await createPostListOutlet (), `
        <script type="application/ld+json">
        {
        "@context": "http://schema.org",
        "@type": "WebSite",
        "url": "https://hub.nizika.monster",
        "potentialAction": {
         "@type": "SearchAction",
         "target": "https://hub.nizika.monster/posts?tags={search_term}",
         "query-input": "required name=search_term"
         }
        }
        </script>`],
    ...tags,
    ...posts,
    ['/wiki', `Wiki | ${ SITE_TITLE }`],
    ...wikiPages]

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${ routes.map (([route]) => `  <url>
    <loc>${ DOMAIN }${ route }</loc>
    <lastmod>${ formatDate () }</lastmod>
    <changefreq>daily</changefreq>
  </url>`).join ('\n') }
</urlset>`

const rss = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>The Series of Bocchi the Rock! Creatures Hub Feed</title>
    <link>${ DOMAIN }/</link>
    <description>最新の投稿、タグ、Wiki ページの一覧</description>
    <language>ja</language>
    <pubDate>${ (new Date).toUTCString () }</pubDate>
${ routes.map (([route, title]) => `    <item>
      <title>${ title }</title>
      <link>${ DOMAIN }${ route }</link>
      <guid>${ DOMAIN }${ route }</guid>
      <pubDate>${ (new Date).toUTCString () }</pubDate>
    </item>`).join ('\n') }
  </channel>
</rss>`

fs.writeFileSync (path.resolve ('dist/sitemap.xml'), xml)
fs.writeFileSync (path.resolve ('dist/rss.xml'), rss)

const baseHTML = fs.readFileSync (path.resolve ('dist/index.html'), 'utf8')
let htaccess = fs.readFileSync (path.resolve ('dist/.htaccess'), 'utf8')
routes.forEach (([route, title, outlet, helmet]) => {
  const fileName = (
      route === '/'
      ? 'index.html'
      : `${ crypto.createHash ('sha256').update (encodeURIComponent (route)).digest ('hex') }.html`)

  let html = baseHTML.replace (/(?<=<title>).*?(?=<\/title>)/, title)
  html = html.replace ('<!-- outlet -->', outlet || '')
  html = html.replace ('<!-- helmet -->', helmet || '')
  fs.writeFileSync (path.resolve (`dist/${ fileName }`), html)

  const [routeBase, q] = route.split ('?')
  if (route !== '/')
    {
      htaccess = htaccess.replace ('# routes #', `
          RewriteCond %{REQUEST_URI} ^${ routeBase }$
          ${ q ? `RewriteCond %{QUERY_STRING} (^|&)${ q }(&|$)` : '' }
          RewriteRule ^ /${ fileName } [L]
          # routes #
          `)
    }
})
fs.writeFileSync (path.resolve ('dist/.htaccess'), htaccess.replace ('# routes #', ''))
