<script lang="ts">
  import Loading from "../Base/Loading.svelte"
  import MaplibreMap from "../Map/MaplibreMap.svelte"
  import { Utils } from "../../Utils"
  import { Store, UIEventSource } from "../../Logic/UIEventSource"
  import FilteredLayer from "../../Models/FilteredLayer"
  import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
  import type { SpecialVisualizationState } from "../SpecialVisualization"
  import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
  import ShowDataLayer from "../Map/ShowDataLayer"
  import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
  import SpecialVisualizations from "../SpecialVisualizations"
  import type { AutoAction } from "./AutoApplyButtonVis"
  import Tr from "../Base/Tr.svelte"
  import Translations from "../i18n/Translations"

  /**
   * The ids to handle. Might be data from an external dataset, we cannot assume an OSM-id
   */
  export let ids: Store<string[] | undefined>
  export let state: SpecialVisualizationState
  export let options: {
    target_layer_id: string
    targetTagRendering: string
    text: string
    icon: string
  }
  let buttonState: UIEventSource<"idle" | "running" | "done" | { error: string }> =
    new UIEventSource<"idle" | "running" | "done" | { error: string }>("idle")
  let tagRenderingConfig: TagRenderingConfig
  let appliedNumberOfFeatures = new UIEventSource<number>(0)

  let layer: FilteredLayer = state.layerState.filteredLayers.get(options.target_layer_id)
  tagRenderingConfig = layer.layerDef.tagRenderings.find(
    (tr) => tr.id === options.targetTagRendering
  )

  const mlmap = new UIEventSource(undefined)
  const mla = new MapLibreAdaptor(mlmap, {
    rasterLayer: state.mapProperties.rasterLayer,
  })
  mla.allowZooming.setData(false)
  mla.allowMoving.setData(false)

  const features = ids.mapD((ids) =>
    ids.map((id) => state.indexedFeatures.featuresById.data.get(id))
  )

  new ShowDataLayer(mlmap, {
    features: StaticFeatureSource.fromGeojson(features),
    zoomToFeatures: true,
    layer: layer.layerDef,
  })

  features.addCallbackAndRunD((f) => console.log("Features are now", f))

  async function applyAllChanges() {
    buttonState.set("running")
    try {
      const target_feature_ids = ids.data
      console.log("Applying auto-action on " + target_feature_ids.length + " features")
      const appliedOn: string[] = []
      for (let i = 0; i < target_feature_ids.length; i++) {
        const targetFeatureId = target_feature_ids[i]
        console.log("Handling", targetFeatureId)
        const feature = state.indexedFeatures.featuresById.data.get(targetFeatureId)
        const featureTags = state.featureProperties.getStore(targetFeatureId)
        const rendering = tagRenderingConfig.GetRenderValue(featureTags.data).txt
        const specialRenderings = Utils.NoNull(
          SpecialVisualizations.constructSpecification(rendering)
        ).filter((v) => typeof v !== "string" && v.func["supportsAutoAction"] === true)

        if (specialRenderings.length == 0) {
          console.warn(
            "AutoApply: feature " +
              targetFeatureId +
              " got a rendering without supported auto actions:",
            rendering
          )
        }

        for (const specialRendering of specialRenderings) {
          if (typeof specialRendering === "string") {
            continue
          }
          const action = <AutoAction>specialRendering.func
          await action.applyActionOn(feature, state, featureTags, specialRendering.args)
        }
        appliedOn.push(targetFeatureId)
        if (i % 50 === 0) {
          await state.changes.flushChanges("Auto button: intermediate save")
        }
        appliedNumberOfFeatures.setData(i + 1)
      }
      console.log("Flushing changes...")
      await state.changes.flushChanges("Auto button: done")
      buttonState.setData("done")
      console.log(
        "Applied changes onto",
        appliedOn.length,
        "items, unique IDs:",
        new Set(appliedOn).size
      )
    } catch (e) {
      console.error("Error while running autoApply: ", e)
      buttonState.setData({ error: e })
    }
  }

  const t = Translations.t.general.add.import
</script>

{#if !state.theme.official && !state.featureSwitchIsTesting.data}
  <div class="alert">
    The auto-apply button is only available in official themes (or in testing mode)
  </div>
  <Tr t={t.howToTest} />
{:else if ids === undefined}
  <Loading>Gathering which elements support auto-apply...</Loading>
{:else if tagRenderingConfig === undefined}
  <div class="alert">Target tagrendering {options.targetTagRendering} not found"</div>
{:else if $ids.length === 0}
  <div>No elements found to perform action</div>
{:else if $buttonState.error !== undefined}
  <div class="flex flex-col">
    <div class="alert">Something went wrong</div>
    <div>{$buttonState.error}</div>
  </div>
{:else if $buttonState === "done"}
  <div class="thanks">All done!</div>
{:else if $buttonState === "running"}
  <Loading>
    Applying changes, currently at {$appliedNumberOfFeatures} / {$ids.length}
  </Loading>
{:else if $buttonState === "idle"}
  <div class="flex flex-col">
    <button
      on:click={() => {
        applyAllChanges()
      }}
    >
      <img class="h-8 w-8" alt="" src={options.icon} />
      {options.text}
    </button>

    <div class="h-48 w-full">
      <MaplibreMap mapProperties={mla} map={mlmap} />
    </div>

    <div class="subtle link-underline">
      The following objects will be updated:
      <div class="flex flex-wrap gap-x-2">
        {#each $ids as featId}
          {#if layer.layerDef.source.geojsonSource === undefined}
            <a href={"https://openstreetmap.org/" + featId} target="_blank">{featId}</a>
          {:else}
            <div>
              {featId}
            </div>
          {/if}
        {/each}
      </div>
    </div>
  </div>
{:else}
  <div>Not supposed to show this... AutoApplyButton has invalid buttonstate: {$buttonState}</div>
{/if}
