import { VariableUiElement } from "../Base/VariableUIElement"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import { BBox } from "../../Logic/BBox"
import Loc from "../../Models/Loc"
import Hotkeys from "../Base/Hotkeys"
import Translations from "../i18n/Translations"
import Constants from "../../Models/Constants"

/**
 * Displays an icon depending on the state of the geolocation.
 * Will set the 'lock' if clicked twice
 */
export class GeolocationControl extends VariableUiElement {
    constructor(
        geolocationHandler: GeoLocationHandler,
        state: {
            locationControl: UIEventSource<Loc>
            currentBounds: UIEventSource<BBox>
        }
    ) {
        const lastClick = new UIEventSource<Date>(undefined)
        lastClick.addCallbackD((date) => {
            geolocationHandler.geolocationState.requestMoment.setData(date)
        })
        const lastClickWithinThreeSecs = lastClick.map((lastClick) => {
            if (lastClick === undefined) {
                return false
            }
            const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
            return timeDiff <= 3
        })
        const lastRequestWithinTimeout = geolocationHandler.geolocationState.requestMoment.map(
            (date) => {
                if (date === undefined) {
                    return false
                }
                const timeDiff = (new Date().getTime() - date.getTime()) / 1000
                console.log("Timediff", timeDiff)
                return timeDiff <= Constants.zoomToLocationTimeout
            }
        )
        const geolocationState = geolocationHandler?.geolocationState
        super(
            geolocationState?.permission?.map(
                (permission) => {
                    if (permission === "denied") {
                        return Svg.location_refused_svg()
                    }
                    if (geolocationState.isLocked.data) {
                        return Svg.location_locked_svg()
                    }

                    if (geolocationState.currentGPSLocation.data === undefined) {
                        if (permission === "prompt") {
                            return Svg.location_empty_svg()
                        }
                        // Position not yet found, but permission is either requested or granted: we spin to indicate activity
                        const icon =
                            !geolocationHandler.mapHasMoved.data || lastRequestWithinTimeout.data
                                ? Svg.location_svg()
                                : Svg.location_empty_svg()
                        return icon
                            .SetClass("cursor-wait")
                            .SetStyle("animation: spin 4s linear infinite;")
                    }

                    // We have a location, so we show a dot in the center

                    if (lastClickWithinThreeSecs.data) {
                        return Svg.location_unlocked_svg()
                    }

                    // We have a location, so we show a dot in the center
                    return Svg.location_svg()
                },
                [
                    geolocationState.currentGPSLocation,
                    geolocationState.isLocked,
                    geolocationHandler.mapHasMoved,
                    lastClickWithinThreeSecs,
                    lastRequestWithinTimeout,
                ]
            )
        )

        async function handleClick() {
            if (
                geolocationState.permission.data !== "granted" &&
                geolocationState.currentGPSLocation.data === undefined
            ) {
                lastClick.setData(new Date())
                await geolocationState.requestPermission()
            }

            if (geolocationState.isLocked.data === true) {
                // Unlock
                geolocationState.isLocked.setData(false)
                return
            }

            if (geolocationState.currentGPSLocation.data === undefined) {
                // No location is known yet, not much we can do
                lastClick.setData(new Date())
                return
            }

            // A location _is_ known! Let's move to this location
            const currentLocation = geolocationState.currentGPSLocation.data
            const inBounds = state.currentBounds.data.contains([
                currentLocation.longitude,
                currentLocation.latitude,
            ])
            geolocationHandler.MoveMapToCurrentLocation()
            if (inBounds) {
                const lc = state.locationControl.data
                state.locationControl.setData({
                    ...lc,
                    zoom: lc.zoom + 3,
                })
            }

            if (lastClickWithinThreeSecs.data) {
                geolocationState.isLocked.setData(true)
                lastClick.setData(undefined)
                return
            }

            lastClick.setData(new Date())
        }

        this.onClick(handleClick)
        Hotkeys.RegisterHotkey(
            { nomod: "L" },
            Translations.t.hotkeyDocumentation.geolocate,
            handleClick
        )

        lastClick.addCallbackAndRunD((_) => {
            window.setTimeout(() => {
                if (lastClickWithinThreeSecs.data) {
                    lastClick.ping()
                }
            }, 500)
        })
        geolocationHandler.geolocationState.requestMoment.addCallbackAndRunD((_) => {
            window.setTimeout(() => {
                if (lastRequestWithinTimeout.data) {
                    geolocationHandler.geolocationState.requestMoment.ping()
                }
            }, 500)
        })
    }
}