import type { ResultNote } from '../globals'
import { Query } from '../search/query'
import type LocatorPlugin from '../main'
import { LocatorVaultModal } from '../components/modals'

type ResultNoteApi = {
  score: number
  vault: string
  path: string
  basename: string
  foundWords: string[]
  matches: SearchMatchApi[]
  excerpt: string
}

export type SearchMatchApi = {
  match: string
  offset: number
}

let notified = false

/**
 * Callbacks to be called when the search index is ready
 */
let onIndexedCallbacks: Array<() => void> = []

function mapResults(
  plugin: LocatorPlugin,
  results: ResultNote[]
): ResultNoteApi[] {
  return results.map(result => {
    const { score, path, basename, foundWords, matches, content } = result

    const excerpt = plugin.textProcessor.makeExcerpt(
      content,
      matches[0]?.offset ?? -1
    )

    const res: ResultNoteApi = {
      score,
      vault: plugin.app.vault.getName(),
      path,
      basename,
      foundWords,
      matches: matches.map(match => {
        return {
          match: match.match,
          offset: match.offset,
        }
      }),
      excerpt: excerpt,
    }

    return res
  })
}

export function notifyOnIndexed(): void {
  notified = true
  onIndexedCallbacks.forEach(cb => cb())
}

let registed = false

export function registerAPI(plugin: LocatorPlugin): void {
  if (registed) {
    return
  }
  registed = true

  // Url scheme for obsidian://locator?query=foobar
  plugin.registerObsidianProtocolHandler('locator', params => {
    new LocatorVaultModal(plugin, params.query).open()
  })

  const api = getApi(plugin)

  // Public api
  // @ts-ignore
  globalThis['locator'] = api
  // Deprecated
  ;(plugin.app as any).plugins.plugins.locator.api = api
}

export function getApi(plugin: LocatorPlugin) {
  return {
    async search(q: string): Promise<ResultNoteApi[]> {
      const query = new Query(q, {
        ignoreDiacritics: true,
        ignoreArabicDiacritics: true,
      })
      const raw = await plugin.searchEngine.getSuggestions(query)
      return mapResults(plugin, raw)
    },
    registerOnIndexed(cb: () => void): void {
      onIndexedCallbacks.push(cb)
      // Immediately call the callback if the indexing is already ready done
      if (notified) {
        cb()
      }
    },
    unregisterOnIndexed(cb: () => void): void {
      onIndexedCallbacks = onIndexedCallbacks.filter(o => o !== cb)
    },
    refreshIndex: plugin.notesIndexer.refreshIndex,
  }
}
