import Toggle from "../Input/Toggle"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import { SubtleButton } from "../Base/SubtleButton"
import Combine from "../Base/Combine"
import { Button } from "../Base/Button"
import Translations from "../i18n/Translations"
import SplitAction from "../../Logic/Osm/Actions/SplitAction"
import Title from "../Base/Title"
import BaseUIElement from "../BaseUIElement"
import { VariableUiElement } from "../Base/VariableUIElement"
import { LoginToggle } from "./LoginButton"
import SvelteUIElement from "../Base/SvelteUIElement"
import WaySplitMap from "../BigComponents/WaySplitMap.svelte"
import { Feature, Point } from "geojson"
import { WayId } from "../../Models/OsmFeature"
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { Changes } from "../../Logic/Osm/Changes"
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"

export default class SplitRoadWizard extends Combine {
    public dialogIsOpened: UIEventSource<boolean>

    /**
     * A UI Element used for splitting roads
     *
     * @param id: The id of the road to remove
     * @param state: the state of the application
     */
    constructor(
        id: WayId,
        state: {
            layout?: LayoutConfig
            osmConnection?: OsmConnection
            osmObjectDownloader?: OsmObjectDownloader
            changes?: Changes
            indexedFeatures?: IndexedFeatureSource
            selectedElement?: UIEventSource<Feature>
        }
    ) {
        const t = Translations.t.split

        // Contains the points on the road that are selected to split on - contains geojson points with extra properties such as 'location' with the distance along the linestring
        const splitPoints = new UIEventSource<Feature<Point>[]>([])

        const hasBeenSplit = new UIEventSource(false)

        // Toggle variable between show split button and map
        const splitClicked = new UIEventSource<boolean>(false)

        const leafletMap = new UIEventSource<BaseUIElement>(undefined)

        function initMap() {
            ;(async function (
                id: WayId,
                splitPoints: UIEventSource<Feature[]>
            ): Promise<BaseUIElement> {
                return new SvelteUIElement(WaySplitMap, {
                    osmWay: await state.osmObjectDownloader.DownloadObjectAsync(id),
                    splitPoints,
                })
            })(id, splitPoints).then((mapComponent) =>
                leafletMap.setData(mapComponent.SetClass("w-full h-80"))
            )
        }

        // Toggle between splitmap
        const splitButton = new SubtleButton(
            Svg.scissors_svg().SetStyle("height: 1.5rem; width: auto"),
            new Toggle(
                t.splitAgain.Clone().SetClass("text-lg font-bold"),
                t.inviteToSplit.Clone().SetClass("text-lg font-bold"),
                hasBeenSplit
            )
        )

        const splitToggle = new LoginToggle(splitButton, t.loginToSplit.Clone(), state)

        // Save button
        const saveButton = new Button(t.split.Clone(), async () => {
            hasBeenSplit.setData(true)
            splitClicked.setData(false)
            const splitAction = new SplitAction(
                id,
                splitPoints.data.map((ff) => <[number, number]>(<Point>ff.geometry).coordinates),
                {
                    theme: state?.layout?.id,
                },
                5
            )
            await state.changes?.applyAction(splitAction)
            // We throw away the old map and splitpoints, and create a new map from scratch
            splitPoints.setData([])

            // Close the popup. The contributor has to select a segment again to make sure they continue editing the correct segment; see #1219
            state.selectedElement?.setData(undefined)
        })

        saveButton.SetClass("btn btn-primary mr-3")
        const disabledSaveButton = new Button(t.split.Clone(), undefined)
        disabledSaveButton.SetClass("btn btn-disabled mr-3")
        // Only show the save button if there are split points defined
        const saveToggle = new Toggle(
            disabledSaveButton,
            saveButton,
            splitPoints.map((data) => data.length === 0)
        )

        const cancelButton = Translations.t.general.cancel
            .Clone() // Not using Button() element to prevent full width button
            .SetClass("btn btn-secondary mr-3")
            .onClick(() => {
                splitPoints.setData([])
                splitClicked.setData(false)
            })

        cancelButton.SetClass("btn btn-secondary block")

        const splitTitle = new Title(t.splitTitle)

        const mapView = new Combine([
            splitTitle,
            new VariableUiElement(leafletMap),
            new Combine([cancelButton, saveToggle]).SetClass("flex flex-row"),
        ])
        mapView.SetClass("question")
        super([
            Toggle.If(hasBeenSplit, () =>
                t.hasBeenSplit.Clone().SetClass("font-bold thanks block w-full")
            ),
            new Toggle(mapView, splitToggle, splitClicked),
        ])
        splitClicked.addCallback((view) => {
            if (view) {
                initMap()
            }
        })
        this.dialogIsOpened = splitClicked
        const self = this
        splitButton.onClick(() => {
            splitClicked.setData(true)
            self.ScrollIntoView()
        })
    }
}