/**
 * Wikipedia REST API client. No key, no auth. Used for two things:
 *   - Long-form plot summaries when the TMDB overview is thin
 *   - Person biographies + portraits on the People page
 *
 * Docs: https://en.wikipedia.org/api/rest_v1/
 *
 * The summary endpoint takes a URL-encoded title and returns a clean
 * extract plus the leading thumbnail. We resolve titles via a search-first
 * strategy so we don't have to maintain title disambiguation by hand.
 */

const BASE = 'https://en.wikipedia.org'
const REST = `${BASE}/api/rest_v1`
const ACTION = `${BASE}/w/api.php`

export interface WikiSummary {
  title: string
  description?: string
  extract: string
  extract_html?: string
  thumbnail?: { source: string; width: number; height: number }
  originalimage?: { source: string; width: number; height: number }
  content_urls?: { desktop: { page: string }; mobile: { page: string } }
}

export interface WikiSearchResult {
  title: string
  pageid: number
  snippet?: string
}

async function fetchJson<T>(url: string): Promise<T | null> {
  try {
    const res = await fetch(url, { headers: { Accept: 'application/json' } })
    if (!res.ok) return null
    return (await res.json()) as T
  } catch {
    return null
  }
}

/**
 * Resolves a free-text query (movie title, person name) to the best-matching
 * Wikipedia article title. Used when we don't have a Wikidata id.
 */
export async function wikipediaSearch(query: string): Promise<WikiSearchResult[]> {
  if (!query) return []
  const url = `${ACTION}?action=query&list=search&format=json&origin=*&srsearch=${encodeURIComponent(query)}&srlimit=3`
  const data = await fetchJson<{ query?: { search?: WikiSearchResult[] } }>(url)
  return data?.query?.search || []
}

/**
 * Pulls the lead summary + thumbnail for an article title. Title can include
 * spaces; we URL-encode it.
 */
export async function wikipediaSummary(title: string): Promise<WikiSummary | null> {
  if (!title) return null
  return fetchJson<WikiSummary>(`${REST}/page/summary/${encodeURIComponent(title)}`)
}

/**
 * Convenience: search by query, take the first match, fetch its summary.
 * Used for movies/shows/people without Wikidata ids.
 */
export async function wikipediaResolve(query: string): Promise<WikiSummary | null> {
  const hits = await wikipediaSearch(query)
  if (hits.length === 0) return null
  return wikipediaSummary(hits[0].title)
}

/**
 * Pull a specific section's plain-text from a Wikipedia article. Used to
 * surface "Production" / "Themes" content as a trivia block on detail
 * pages. Returns null if the article doesn't have that section.
 *
 * Strategy: use the parse API with `prop=sections|text` to find the
 * section index, then fetch that section as wikitext stripped to plain
 * paragraphs.
 */
export async function wikipediaSection(
  title: string,
  sectionName: string,
): Promise<{ title: string; section: string; extract: string } | null> {
  if (!title || !sectionName) return null
  const sectionsUrl = `${ACTION}?action=parse&page=${encodeURIComponent(title)}&format=json&origin=*&prop=sections`
  const sections = await fetchJson<{
    parse?: {
      sections?: Array<{ index: string; line: string; level: string }>
    }
  }>(sectionsUrl)
  const list = sections?.parse?.sections || []
  // Top-level only (level "2") and case-insensitive match. Take the first.
  const target = list.find(
    s => s.level === '2' && s.line.toLowerCase() === sectionName.toLowerCase(),
  )
  if (!target) return null
  const sectionUrl = `${ACTION}?action=parse&page=${encodeURIComponent(title)}&format=json&origin=*&prop=text&section=${target.index}&disabletoc=1`
  const html = await fetchJson<{ parse?: { text?: { '*': string } } }>(sectionUrl)
  const raw = html?.parse?.text?.['*'] || ''
  if (!raw) return null
  return { title, section: target.line, extract: stripWikiHtml(raw) }
}

/**
 * Wikipedia's parse API returns the section's raw HTML. We want plain
 * paragraphs - no headings, no infoboxes, no [edit] markers, no
 * citation superscripts. The pipeline below applies the strips in
 * order so each later step gets a smaller, cleaner input.
 *
 * Order matters: remove structured non-prose (style, references, edit
 * links, headings, tables, navboxes) BEFORE the generic tag-stripping
 * pass, otherwise their text content leaks into the output and merges
 * with the surrounding prose.
 */
function stripWikiHtml(raw: string): string {
  if (!raw) return ''
  let text = raw
    // 1. Drop entirely-non-prose blocks. Each gets matched as a unit
    //    so their text content (heading words, edit-link text, etc.)
    //    disappears with the wrapping tags.
    .replace(/<style[\s\S]*?<\/style>/gi, '')
    .replace(/<script[\s\S]*?<\/script>/gi, '')
    .replace(/<sup[^>]*class="[^"]*reference[^"]*"[^>]*>[\s\S]*?<\/sup>/gi, '')
    // Edit links: match both double and single quoted class attrs, and
    // also catch the bracket wrappers that sometimes leak through.
    .replace(/<span[^>]*class=["'][^"']*mw-editsection[^"']*["'][^>]*>[\s\S]*?<\/span>/gi, '')
    .replace(/<h[1-6][^>]*>[\s\S]*?<\/h[1-6]>/gi, '\n\n')
    .replace(/<table[\s\S]*?<\/table>/gi, '')
    .replace(/<figure[\s\S]*?<\/figure>/gi, '')
    .replace(/<div[^>]*class=["'][^"']*(?:thumb|infobox|navbox|hatnote|reflist|mw-references|gallery)[^"']*["'][\s\S]*?<\/div>/gi, '')
    // 2. Preserve paragraph + line breaks before flattening tags.
    .replace(/<\/p>/gi, '\n\n')
    .replace(/<br\s*\/?>/gi, '\n')
    .replace(/<li[^>]*>/gi, '\n- ')
    .replace(/<\/li>/gi, '')
    // 3. Strip remaining tags.
    .replace(/<[^>]+>/g, '')
    // 4. Citation noise that didn't come wrapped in tags.
    .replace(/\[\s*\d+\s*\]/g, '')
    .replace(/\[\s*[a-z]\s*\]/g, '')
    .replace(/\[\s*(citation needed|clarification needed|when\?|who\?|why\?)\s*\]/gi, '')
    // 5. Stray edit markers that leaked through (e.g. standalone
    //    brackets or "Edit" at the start of the text).
    .replace(/^\s*\[?\s*edit\s*\]?\s*/i, '')
    .replace(/\n\s*\[?\s*edit\s*\]?\s*/gi, '\n')

  // 6. Decode ALL HTML entities (numeric, named, hex) via DOM so we
  //    don't have to maintain an exhaustive regex list.
  if (typeof document !== 'undefined') {
    const tmp = document.createElement('textarea')
    tmp.innerHTML = text
    text = tmp.value
  } else {
    // Fallback for SSR / test environments: cover the common ones.
    text = text
      .replace(/&nbsp;/g, ' ')
      .replace(/&amp;/g, '&')
      .replace(/&quot;/g, '"')
      .replace(/&apos;/g, "'")
      .replace(/&#39;/g, "'")
      .replace(/&#039;/g, "'")
      .replace(/&#8212;/g, '-')
      .replace(/&#8217;/g, "'")
      .replace(/&#8230;/g, '...')
      .replace(/&lt;/g, '<')
      .replace(/&gt;/g, '>')
  }

  // 7. Whitespace cleanup. Collapse runs of spaces, trim stray
  //    indents around newlines, normalise blank-line gaps to one.
  return text
    .replace(/[ \t]+/g, ' ')
    .replace(/[ \t]*\n[ \t]*/g, '\n')
    .replace(/\n{3,}/g, '\n\n')
    .trim()
}
