import { extractTextFromAst } from '~/utils/content-ast'

export interface PostSearchFilters {
  title: boolean
  description: boolean
  content: boolean
  tags: boolean
}

export interface PostSearchResult {
  post: any
  matchedLines: string[]
}

function parseQueryTerms(query: string): string[] {
  const terms: string[] = []
  const re = /"([^"]+)"|(\S+)/g
  let m: RegExpExecArray | null
  while ((m = re.exec(query)) !== null) {
    const t = (m[1] ?? m[2] ?? '').trim().toLowerCase()
    if (t) terms.push(t)
  }
  return terms
}

function highlightText(text: string, terms: string[]): string {
  if (!terms.length) return text
  const escaped = terms
    .map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
    .sort((a, b) => b.length - a.length)
  const regex = new RegExp(`(${escaped.join('|')})`, 'gi')
  return text.replace(regex, '<mark class="search-highlight">$1</mark>')
}

function getMatchedLines(plainText: string, terms: string[]): string[] {
  if (!terms.length || !plainText) return []
  const lines = plainText.split('\n')
  const matched: string[] = []
  for (const line of lines) {
    const lower = line.toLowerCase()
    if (terms.every((t) => lower.includes(t))) {
      const trimmed = line.trim()
      if (
        trimmed
        && trimmed.length > 10
        && !trimmed.startsWith('#')
        && !trimmed.startsWith('.')
        && !trimmed.includes('{')
        && !trimmed.includes('}')
        && !trimmed.includes(':')
        && !trimmed.includes(';')
        && !trimmed.match(/^[a-z][\w-]*[\s]*\{/)
        && !trimmed.match(/^\.shiki/)
        && !trimmed.match(/^var\(--/)
        && !trimmed.match(/^html\b/)
        && !trimmed.match(/^pre\b/)
        && !trimmed.match(/^@/)
      ) {
        matched.push(trimmed)
      }
    }
  }
  return matched.slice(0, 10)
}

export function usePostSearch(
  allPosts: Ref<any[] | null>,
  searchQuery: Ref<string>,
  filters: Ref<PostSearchFilters>,
) {
  const searchResults = computed<PostSearchResult[]>(() => {
    if (!allPosts.value || !searchQuery.value.trim()) {
      return allPosts.value?.map((p) => ({ post: p, matchedLines: [] })) || []
    }

    const terms = parseQueryTerms(searchQuery.value)
    if (!terms.length) return allPosts.value.map((p) => ({ post: p, matchedLines: [] }))

    const results: PostSearchResult[] = []

    for (const post of allPosts.value) {
      const title = (post.title || '').toLowerCase()
      const desc = (post.description || '').toLowerCase()

      const matchTitle = filters.value.title && terms.some((t) => title.includes(t))
      const matchDesc = filters.value.description && terms.some((t) => desc.includes(t))
      const matchTags = filters.value.tags && (post.tags || []).some((tag: string) => terms.some((t) => tag.toLowerCase().includes(t)))

      let matchContent = false
      let matchedLines: string[] = []
      if (filters.value.content) {
        const plainText = extractTextFromAst(post.body?.value || post.body || null).toLowerCase()
        matchContent = terms.some((t) => plainText.includes(t))
        if (matchContent) {
          matchedLines = getMatchedLines(
            extractTextFromAst(post.body?.value || post.body || null),
            terms,
          )
        }
      }

      if (matchTitle || matchDesc || matchContent || matchTags) {
        results.push({ post, matchedLines })
      }
    }

    return results
  })

  const filteredPosts = computed(() => searchResults.value.map((r) => r.post))

  function highlight(text: string): string {
    if (!searchQuery.value.trim()) return text
    return highlightText(text, parseQueryTerms(searchQuery.value))
  }

  function getTerms(): string[] {
    return parseQueryTerms(searchQuery.value)
  }

  return {
    searchResults,
    filteredPosts,
    highlight,
    getTerms,
  }
}
