<script lang="ts">
  /**
   * Allows to search through wikidata and to select one value
   */

  import Translations from "../../i18n/Translations"
  import Tr from "../../Base/Tr.svelte"
  import { ImmutableStore, Store, Stores, UIEventSource } from "../../../Logic/UIEventSource"
  import Wikidata, { WikidataResponse } from "../../../Logic/Web/Wikidata"
  import Locale from "../../i18n/Locale"
  import Loading from "../../Base/Loading.svelte"
  import Wikidatapreview from "../../Wikipedia/Wikidatapreview.svelte"
  import { Utils } from "../../../Utils"
  import WikidataValidator from "../Validators/WikidataValidator"
  import Searchbar from "../../Base/Searchbar.svelte"

  const t = Translations.t.general.wikipedia

  export let searchValue = new UIEventSource(undefined)
  export let placeholder = t.searchWikidata
  export let allowMultiple = true

  export let notInstanceOf: number[] = []
  export let instanceOf: number[] = []

  export let value: UIEventSource<string>

  let selectedWikidataSingle: WikidataResponse = undefined
  let selectedMany: Record<string, boolean> = {}
  let previouslySeen = new Map<string, WikidataResponse>()

  $: {
    if (selectedWikidataSingle) {
      value.setData(selectedWikidataSingle.id)
    }
  }

  $: {
    const v = []
    for (const id in selectedMany) {
      if (selectedMany[id]) {
        v.push(id)
      }
    }
    value.setData(v.join(";"))
  }

  let tooShort = new ImmutableStore<{ success: WikidataResponse[] }>({ success: undefined })

  let searchResult: Store<{ success?: WikidataResponse[]; error?: any }> = searchValue.bind(
    (searchText) => {
      if (searchText.length < 3 && !searchText.match(/[qQ][0-9]+/)) {
        return tooShort
      }
      const lang = Locale.language.data
      const key = lang + ":" + searchText
      let promise = WikidataValidator._searchCache.get(key)
      if (promise === undefined) {
        promise = Wikidata.searchAndFetch(searchText, {
          lang,
          maxCount: 5,
          notInstanceOf,
          instanceOf,
        })
        WikidataValidator._searchCache.set(key, promise)
      }
      return Stores.FromPromiseWithErr(promise)
    }
  )

  let selectedWithoutSearch: Store<WikidataResponse[]> = searchResult.map((sr) => {
    for (const wikidataItem of sr?.success ?? []) {
      previouslySeen.set(wikidataItem.id, wikidataItem)
    }
    let knownIds: Set<string> = new Set(sr?.success?.map((item) => item.id))
    const seen = [selectedWikidataSingle]
    for (const id in selectedMany) {
      if (selectedMany[id]) {
        const item = previouslySeen.get(id)
        seen.push(item)
      }
    }
    return Utils.NoNull(seen).filter((i) => !knownIds.has(i.id))
  })
</script>

<h3>
  <Tr t={Translations.t.general.wikipedia.searchWikidata} />
</h3>

<form>
  <Searchbar value={searchValue} {placeholder} />

  {#if $searchValue.trim().length === 0}
    <Tr cls="w-full flex justify-center p-4" t={t.doSearch} />
  {:else if $searchValue.trim().length < 3}
    <Tr t={t.searchToShort} />
  {:else if $searchResult === undefined}
    <div class="flex w-full justify-center p-4">
      <Loading>
        <Tr t={Translations.t.general.loading} />
      </Loading>
    </div>
  {:else if $searchResult.error !== undefined}
    <div class="flex w-full justify-center p-4">
      <Tr cls="alert" t={t.failed} />
    </div>
  {:else if $searchResult.success}
    {#if $searchResult.success.length === 0}
      <Tr cls="w-full flex justify-center p-4" t={t.noResults.Subs({ search: $searchValue })} />
    {:else}
      {#each $searchResult.success as wikidata}
        <label class="low-interaction m-4 flex items-center rounded-xl p-2">
          {#if allowMultiple}
            <input type="checkbox" bind:checked={selectedMany[wikidata.id]} />
          {:else}
            <input
              type="radio"
              name="selectedWikidata"
              value={wikidata}
              bind:group={selectedWikidataSingle}
            />
          {/if}

          <Wikidatapreview {wikidata} />
        </label>
      {/each}
    {/if}
  {/if}

  {#each $selectedWithoutSearch as wikidata}
    <label class="low-interaction m-4 flex items-center rounded-xl p-2">
      {#if allowMultiple}
        <input type="checkbox" bind:checked={selectedMany[wikidata.id]} />
      {:else}
        <input
          type="radio"
          name="selectedWikidata"
          value={wikidata}
          bind:group={selectedWikidataSingle}
        />
      {/if}

      <Wikidatapreview {wikidata} />
    </label>
  {/each}
</form>
