---
import { getCollection } from 'astro:content'

export interface Props {
  fallbackLocale?: 'en' | 'ja'
}

const { fallbackLocale = 'en' } = Astro.props

const allDocs = await getCollection('docs')
const docCandidates = allDocs
  .map(entry => {
    const maybeSlug = (entry as { slug?: unknown }).slug
    const slug =
      (typeof maybeSlug === 'string' ? maybeSlug : undefined) ?? entry.id ?? ''
    return { entry, slug }
  })
  .filter(({ slug }) => slug && !slug.endsWith('/404') && slug !== '404')
  .map(({ entry, slug }) => {
    const normalizedSlug = slug.replace(/^\/+|\/+$/g, '')
    const href = `/docs/${normalizedSlug}/`
    const title =
      typeof entry.data?.title === 'string' && entry.data.title.trim()
        ? entry.data.title.trim()
        : normalizedSlug
    return { href, title }
  })

const prefix = `/docs/${fallbackLocale}/`
const fallbackFromLocale = docCandidates
  .filter(c => c.href.startsWith(prefix))
  .slice(0, 3)
const fallbackSuggestions =
  fallbackFromLocale.length >= 3
    ? fallbackFromLocale
    : docCandidates.slice(0, 3)
---

<p class="suggested-404-label"><strong>Suggested:</strong></p>
<ul
  class="suggested-404-list"
  id="suggested-404-list"
  data-fallback-locale={fallbackLocale}
>
  {
    fallbackSuggestions.map(s => (
      <li>
        <a href={s.href}>{s.title}</a>
      </li>
    ))
  }
</ul>

<script define:vars={{ docCandidates }}>
  const DEFAULT_LOCALE = 'en'
  const SUPPORTED_LOCALES = ['en', 'ja']

  const normalizePath = p => {
    if (!p) return '/'
    let path = String(p)
    path = path.split('?')[0]?.split('#')[0] ?? path
    path = path.toLowerCase()
    path = path.replace(/\/+/g, '/')
    if (!path.startsWith('/')) path = `/${path}`
    if (!path.endsWith('/')) path = `${path}/`
    return path
  }

  const localeFromPathname = pathname => {
    const normalized = normalizePath(pathname)
    const afterDocs = normalized.slice('/docs/'.length)
    const first = afterDocs.split('/').filter(Boolean)[0] ?? ''
    if (SUPPORTED_LOCALES.includes(first)) return first
    return DEFAULT_LOCALE
  }

  const pathForMatching = pathname => {
    const normalized = normalizePath(pathname)
    const afterDocs = normalized.slice('/docs/'.length)
    const segments = afterDocs.split('/').filter(Boolean)
    const first = segments[0] ?? ''
    if (SUPPORTED_LOCALES.includes(first)) return normalized
    return normalizePath(`/docs/${DEFAULT_LOCALE}/${segments.join('/')}`)
  }

  const candidatesForLocale = (candidates, locale) =>
    (candidates ?? []).filter(c =>
      normalizePath(c.href).startsWith(`/docs/${locale}/`)
    )

  const levenshtein = (a, b) => {
    const s = a ?? ''
    const t = b ?? ''
    if (s === t) return 0
    if (!s) return t.length
    if (!t) return s.length

    const m = s.length
    const n = t.length
    const dp = new Array(n + 1)
    for (let j = 0; j <= n; j++) dp[j] = j

    for (let i = 1; i <= m; i++) {
      let prev = dp[0]
      dp[0] = i
      for (let j = 1; j <= n; j++) {
        const tmp = dp[j]
        const cost = s[i - 1] === t[j - 1] ? 0 : 1
        dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + cost)
        prev = tmp
      }
    }
    return dp[n]
  }

  const escapeHtml = str =>
    String(str)
      .replaceAll('&', '&amp;')
      .replaceAll('<', '&lt;')
      .replaceAll('>', '&gt;')
      .replaceAll('"', '&quot;')

  const listEl = document.getElementById('suggested-404-list')
  if (listEl) {
    const requested = normalizePath(window.location.pathname)

    if (!requested.startsWith('/docs/')) {
      listEl.replaceChildren()
    } else {
      const activeLocale = localeFromPathname(window.location.pathname)
      const pool = candidatesForLocale(docCandidates, activeLocale)

      if (!pool.length) {
        listEl.replaceChildren()
      } else {
        const requestedForMatch = pathForMatching(window.location.pathname)
        const scored = pool.map(c => {
          const hrefNorm = normalizePath(c.href)
          const dist = levenshtein(requestedForMatch, hrefNorm)
          return { ...c, score: dist }
        })

        scored.sort((a, b) => a.score - b.score || a.href.localeCompare(b.href))

        const top = scored.slice(0, 3)
        listEl.innerHTML = top
          .map(
            s =>
              `<li><a href="${escapeHtml(s.href)}">${escapeHtml(s.title)}</a></li>`
          )
          .join('')
      }
    }
  }
</script>

<style is:global>
  .suggested-404-label {
    margin: 0.35rem 0 0.2rem;
  }

  .suggested-404-list {
    margin: 0.15rem 0 0;
    padding-left: 1.25rem;
    text-align: left;
  }

  .markdown-content > p.suggested-404-label {
    margin: 0.35rem 0 0.2rem !important;
  }

  .markdown-content > ul.suggested-404-list {
    margin-top: 0.15rem !important;
    margin-bottom: 0 !important;
  }
</style>
