import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
import { UIEventSource } from "../../Logic/UIEventSource"
import { DefaultGuiState } from "../DefaultGuiState"
import BaseUIElement from "../BaseUIElement"
import Translations from "../i18n/Translations"
import { GeoOperations } from "../../Logic/GeoOperations"
import NearbyImages, { NearbyImageOptions, P4CPicture, SelectOneNearbyImage } from "./NearbyImages"
import { SubstitutedTranslation } from "../SubstitutedTranslation"
import { Tag } from "../../Logic/Tags/Tag"
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
import { And } from "../../Logic/Tags/And"
import { SaveButton } from "./SaveButton"
import Lazy from "../Base/Lazy"
import { CheckBox } from "../Input/Checkboxes"
import Slider from "../Input/Slider"
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
import Combine from "../Base/Combine"
import { VariableUiElement } from "../Base/VariableUIElement"
import Toggle from "../Input/Toggle"
import Title from "../Base/Title"
import { MapillaryLinkVis } from "./MapillaryLinkVis"
import { SpecialVisualization } from "../SpecialVisualization"

export class NearbyImageVis implements SpecialVisualization {
    args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [
        {
            name: "mode",
            defaultValue: "expandable",
            doc: "Indicates how this component is initialized. Options are: \n\n- `open`: always show and load the pictures\n- `collapsable`: show the pictures, but a user can collapse them\n- `expandable`: shown by default; but a user can collapse them.",
        },
        {
            name: "mapillary",
            defaultValue: "true",
            doc: "If 'true', includes a link to mapillary on this location.",
        },
    ]
    docs =
        "A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
    funcName = "nearby_images"

    constr(
        state: FeaturePipelineState,
        tagSource: UIEventSource<any>,
        args: string[],
        guistate: DefaultGuiState
    ): BaseUIElement {
        const t = Translations.t.image.nearbyPictures
        const mode: "open" | "expandable" | "collapsable" = <any>args[0]
        const feature = state.allElements.ContainingFeatures.get(tagSource.data.id)
        const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
        const id: string = tagSource.data["id"]
        const canBeEdited: boolean = !!id?.match("(node|way|relation)/-?[0-9]+")
        const selectedImage = new UIEventSource<P4CPicture>(undefined)

        let saveButton: BaseUIElement = undefined
        if (canBeEdited) {
            const confirmText: BaseUIElement = new SubstitutedTranslation(
                t.confirm,
                tagSource,
                state
            )

            const onSave = async () => {
                console.log("Selected a picture...", selectedImage.data)
                const osmTags = selectedImage.data.osmTags
                const tags: Tag[] = []
                for (const key in osmTags) {
                    tags.push(new Tag(key, osmTags[key]))
                }
                await state?.changes?.applyAction(
                    new ChangeTagAction(id, new And(tags), tagSource.data, {
                        theme: state?.layoutToUse.id,
                        changeType: "link-image",
                    })
                )
            }
            saveButton = new SaveButton(
                selectedImage,
                state.osmConnection,
                confirmText,
                t.noImageSelected
            )
                .onClick(onSave)
                .SetClass("flex justify-end")
        }

        const nearby = new Lazy(() => {
            const towardsCenter = new CheckBox(t.onlyTowards, false)

            const radiusValue =
                state?.osmConnection?.GetPreference("nearby-images-radius", "300").sync(
                    (s) => Number(s),
                    [],
                    (i) => "" + i
                ) ?? new UIEventSource(300)

            const radius = new Slider(25, 500, {
                value: radiusValue,
                step: 25,
            })
            const alreadyInTheImage = AllImageProviders.LoadImagesFor(tagSource)
            const options: NearbyImageOptions & { value } = {
                lon,
                lat,
                searchRadius: 500,
                shownRadius: radius.GetValue(),
                value: selectedImage,
                blacklist: alreadyInTheImage,
                towardscenter: towardsCenter.GetValue(),
                maxDaysOld: 365 * 5,
            }
            const slideshow = canBeEdited
                ? new SelectOneNearbyImage(options, state)
                : new NearbyImages(options, state)
            const controls = new Combine([
                towardsCenter,
                new Combine([
                    new VariableUiElement(
                        radius.GetValue().map((radius) => t.withinRadius.Subs({ radius }))
                    ),
                    radius,
                ]).SetClass("flex justify-between"),
            ]).SetClass("flex flex-col")
            return new Combine([
                slideshow,
                controls,
                saveButton,
                new MapillaryLinkVis().constr(state, tagSource, []).SetClass("mt-6"),
            ])
        })

        let withEdit: BaseUIElement = nearby
        if (canBeEdited) {
            withEdit = new Combine([t.hasMatchingPicture, nearby]).SetClass("flex flex-col")
        }

        if (mode === "open") {
            return withEdit
        }
        const toggleState = new UIEventSource<boolean>(mode === "collapsable")
        return new Toggle(
            new Combine([new Title(t.title), withEdit]),
            new Title(t.browseNearby).onClick(() => toggleState.setData(true)),
            toggleState
        )
    }
}