import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
import { Changes } from "../../Logic/Osm/Changes"
import {
    SpecialVisualization,
    SpecialVisualizationState,
    SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
import SvelteUIElement from "../Base/SvelteUIElement"
import { Feature } from "geojson"
import AutoApplyButton from "./AutoApplyButton.svelte"

export interface AutoAction extends SpecialVisualization {
    supportsAutoAction: boolean

    applyActionOn(
        feature: Feature,
        state: {
            theme: ThemeConfig
            changes: Changes
            indexedFeatures: IndexedFeatureSource
        },
        tagSource: UIEventSource<Record<string, string>>,
        argument: string[]
    ): Promise<void>
}

export default class AutoApplyButtonVis implements SpecialVisualizationSvelte {
    public readonly docs: string
    public readonly funcName: string = "auto_apply"
    public readonly needsUrls = []
    public readonly group = "data_import"
    public readonly args: {
        name: string
        defaultValue?: string
        doc: string
        required?: boolean
    }[] = [
        {
            name: "target_layer",
            doc: "The layer that the target features will reside in",
            required: true,
        },
        {
            name: "target_feature_ids",
            doc: "The key, of which the value contains a list of ids",
            required: true,
        },
        {
            name: "tag_rendering_id",
            doc: "The ID of the tagRendering containing the autoAction. This tagrendering will be calculated. The embedded actions will be executed",
            required: true,
        },
        {
            name: "text",
            doc: "The text to show on the button",
            required: true,
        },
        {
            name: "icon",
            doc: "The icon to show on the button",
            defaultValue: "./assets/svg/robot.svg",
        },
    ]

    constructor(allSpecialVisualisations: SpecialVisualization[]) {
        this.docs = AutoApplyButtonVis.generateDocs(
            allSpecialVisualisations
                .filter((sv) => sv["supportsAutoAction"] === true)
                .map((sv) => sv.funcName)
        )
    }

    private static generateDocs(supportedActions: string[]): string {
        return `
        A button to run many actions for many features at once.
        To effectively use this button, you'll need some ingredients:

        1. A target layer with features for which an action is defined in a tag rendering. The following special visualisations support an autoAction: ${supportedActions.join(
            ", "
        )}
        2. A host feature to place the auto-action on. This can be a big outline (such as a city). Another good option for this is the layer [current_view](./BuiltinLayers.md#current_view)
        3. Then, use a calculated tag on the host feature to determine the overlapping object ids
        4. At last, add this component`
    }

    constr(
        state: SpecialVisualizationState,
        tagSource: UIEventSource<Record<string, string>>,
        argument: string[]
    ): SvelteUIElement {
        const target_layer_id = argument[0]
        const targetTagRendering = argument[2]
        const text = argument[3]
        const icon = argument[4]
        const options = {
            target_layer_id,
            targetTagRendering,
            text,
            icon,
        }

        const to_parse: UIEventSource<string[]> = new UIEventSource<string[]>(undefined)
        Stores.Chronic(500, () => to_parse.data === undefined)
            .map(() => {
                const applicable = <string | string[]>tagSource.data[argument[1]]
                if (typeof applicable === "string") {
                    return <string[]>JSON.parse(applicable)
                } else {
                    return applicable
                }
            })
            .addCallbackAndRunD((data) => {
                to_parse.set(data)
            })

        const stableIds: Store<string[]> = Stores.ListStabilized(to_parse).map((ids) => {
            if (typeof ids === "string") {
                ids = JSON.parse(ids)
            }
            return ids.map((id) => id)
        })
        return new SvelteUIElement(AutoApplyButton, { state, ids: stableIds, options })
    }

    getLayerDependencies(args: string[]): string[] {
        return [args[0]]
    }
}
