<script lang="ts">
  import type { Feature } from "geojson"
  import { Store, UIEventSource } from "../../Logic/UIEventSource"
  import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"
  import { OsmObject } from "../../Logic/Osm/OsmObject"
  import Loading from "../Base/Loading.svelte"
  import { HistoryUtils } from "./HistoryUtils"
  import * as favourite from "../../../public/assets/generated/layers/favourite.json"
  import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
  import Tr from "../Base/Tr.svelte"
  import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
  import Translations from "../i18n/Translations"
  import TagRenderingChart from "../BigComponents/TagRenderingChart"
  import ToSvelte from "../Base/ToSvelte.svelte"
  import type { TagRenderingConfigJson } from "../../Models/ThemeConfig/Json/TagRenderingConfigJson"
  import { Or } from "../../Logic/Tags/Or"
  import { Utils } from "../../Utils"

  export let onlyShowUsername: string[]
  export let features: Feature[]

  let usernames = new Set(onlyShowUsername)

  const downloader = new OsmObjectDownloader()
  let allHistories: UIEventSource<OsmObject[][]> = UIEventSource.FromPromise(
    Promise.all(features.map((f) => downloader.downloadHistory(f.properties.id)))
  )
  let allDiffs: Store<
    {
      key: string
      value?: string
      oldValue?: string
      step: OsmObject
    }[]
  > = allHistories.mapD((histories) => HistoryUtils.fullHistoryDiff(histories, usernames))

  // We use the favourite-layer as it contains _all_ questions
  const trs = favourite.tagRenderings.map(
    (tr) => new TagRenderingConfig(<TagRenderingConfigJson>tr)
  )

  function detectQuestion(key: string): TagRenderingConfig {
    const byKey = trs.find((tr) => tr.freeform?.key === key)
    if (byKey) {
      return byKey
    }
    return trs.find((tr) =>
      tr.mappings.some((mapping) => {
        const ifTags = Or.construct(Utils.NoNull([mapping.if, mapping.alsoShowIf]))
        const keys = ifTags.usedKeys()
        return keys.some((k) => k == key)
      })
    )
  }

  const mergedCount: Store<
    {
      key: string
      tr: TagRenderingConfig
      count: number
      values: { value: string; count: number }[]
      features: Feature[]
    }[]
  > = allDiffs.mapD((allDiffs) => {
    const keyCounts = new Map<string, Map<string, OsmObject[]>>()
    for (const diff of allDiffs) {
      const k = diff.key
      if (!keyCounts.has(k)) {
        keyCounts.set(k, new Map<string, OsmObject[]>())
      }
      const valueCounts = keyCounts.get(k)
      const v = diff.value ?? ""
      const oldFeaturesList = valueCounts.get(v) ?? []
      valueCounts.set(v, [...oldFeaturesList, diff.step])
    }

    const perKey: {
      key: string
      tr: TagRenderingConfig
      count: number
      values: { value: string; count: number }[]
      features: Feature[]
    }[] = []
    keyCounts.forEach((values: Map<string, OsmObject[]>, key: string) => {
      const keyTotal: { value: string; features: Feature[] }[] = []
      values.forEach((count, value) => {
        keyTotal.push({ value, features: count.map((step) => step.asGeoJson()) })
      })
      let countForKey: Feature[] = []
      for (const { features } of keyTotal) {
        countForKey.push(...features)
      }
      keyTotal.sort((a, b) => b.features.length - a.features.length)
      const tr = detectQuestion(key)
      perKey.push({
        count: countForKey.length,
        tr,
        key,
        values: keyTotal.map(({ value, features }) => ({
          value,
          count: features.length,
        })),
        features: countForKey,
      })
    })
    perKey.sort((a, b) => b.count - a.count)

    return perKey
  })

  const t = Translations.t.inspector
</script>

{#if allHistories === undefined}
  <Loading />
{:else if $allDiffs !== undefined}
  {#each $mergedCount as diff}
    <h3>
      {#if diff.tr}
        <Tr t={diff.tr.question} />
      {:else}
        {diff.key}
      {/if}
    </h3>
    <AccordionSingle>
      <span slot="header">
        <Tr t={t.answeredCountTimes.Subs(diff)} />
      </span>
      <ul>
        {#each diff.values as value}
          <li>
            <b>{value.value}</b>
            {#if value.count > 1}
              - {value.count}
            {/if}
          </li>
        {/each}
      </ul>
      {#if diff.tr}
        <div class="h-48 w-48">
          <ToSvelte
            construct={new TagRenderingChart(diff.features, diff.tr, {
              groupToOtherCutoff: 0,
              chartType: "pie",
              sort: true,
            })}
          />
        </div>
      {:else}
        Could not create a graph - this item type has no associated question
      {/if}
    </AccordionSingle>
  {/each}
{/if}
