<template>
    <div style="position: relative">
        <!-- <Map className="h-36" :center="state.center" :zoom="state.zoom"> // map component content </Map> -->
        <div :id="mapId" class="rounded">
            <div class="dark:bg-slate-900 bg-slate flex flex-col">
                <ZoomControlComponent ref="zoom" :mapId="mapId" />
                <DrawControlComponent ref="draw" :mapId="mapId" :southWest="southWest" :northEast="northEast" />
            </div>
        </div>
        <div class="gba-control-validate btn-group-vertical">
            <button
                class="min-w-27 inline-flex cursor-pointer justify-center items-center whitespace-nowrap focus:outline-none transition-colors duration-150 border rounded ring-blue-700 text-black text-sm p-1"
                type="button"
                @click.stop.prevent="validateBoundingBox"
                :class="[validBoundingBox ? 'cursor-not-allowed bg-green-500 is-active' : 'bg-red-500 ']"
            >
                <!-- <BaseIcon v-if="mdiMapCheckOutline" :path="mdiMapCheckOutline" /> -->
                {{ label }}
            </button>
        </div>
    </div>
</template>

<script lang="ts">
import { EventEmitter } from './EventEmitter';
import { Component, Vue, Prop, Ref } from 'vue-facing-decorator';
import { Map } from 'leaflet/src/map/index';
import { Control } from 'leaflet/src/control/Control';
import { LatLngBoundsExpression, LatLngBounds } from 'leaflet/src/geo/LatLngBounds';
// import { toLatLng } from 'leaflet/src/geo/LatLng';
import { LatLng } from 'leaflet'; //'leaflet/src/geo/LatLng';
import { tileLayerWMS } from 'leaflet/src/layer/tile/TileLayer.WMS';
import { Attribution } from 'leaflet/src/control/Control.Attribution';
import { mdiMapCheckOutline } from '@mdi/js';
import BaseIcon from '@/Components/BaseIcon.vue';

import { MapOptions } from './MapOptions';
import { LayerOptions, LayerMap } from './LayerOptions';
import { MapService } from '@/Stores/map.service';
import ZoomControlComponent from './zoom.component.vue';
import DrawControlComponent from './draw.component.vue';
import { Coverage } from '@/Dataset';
import { canvas } from 'leaflet/src/layer/vector/Canvas';
import { svg } from 'leaflet/src/layer/vector/SVG';
import Notification from '@/utils/toast';

Map.include({
    // @namespace Map; @method getRenderer(layer: Path): Renderer
    // Returns the instance of `Renderer` that should be used to render the given
    // `Path`. It will ensure that the `renderer` options of the map and paths
    // are respected, and that the renderers do exist on the map.
    getRenderer: function (layer) {
        // @namespace Path; @option renderer: Renderer
        // Use this specific instance of `Renderer` for this path. Takes
        // precedence over the map's [default renderer](#map-renderer).
        var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;

        if (!renderer) {
            renderer = this._renderer = this._createRenderer();
        }

        if (!this.hasLayer(renderer)) {
            this.addLayer(renderer);
        }
        return renderer;
    },

    _getPaneRenderer: function (name) {
        if (name === 'overlayPane' || name === undefined) {
            return false;
        }

        var renderer = this._paneRenderers[name];
        if (renderer === undefined) {
            renderer = this._createRenderer({ pane: name });
            this._paneRenderers[name] = renderer;
        }
        return renderer;
    },

    _createRenderer: function (options) {
        // @namespace Map; @option preferCanvas: Boolean = false
        // Whether `Path`s should be rendered on a `Canvas` renderer.
        // By default, all `Path`s are rendered in a `SVG` renderer.
        return (this.options.preferCanvas && canvas(options)) || svg(options);
    },
});

const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
// const DEFAULT_BASE_LAYER_URL = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors';

@Component({
    name: 'MapComponent',
    components: {
        ZoomControlComponent,
        DrawControlComponent,
        BaseIcon,
    },
})
export default class MapComponent extends Vue {
    /**
     * A map with the given ID is created inside this component.
     * This ID can be used the get the map instance over the map cache service.
     */
    @Prop()
    public mapId: string;

    /**
     * The corresponding leaflet map options (see: https://leafletjs.com/reference-1.3.4.html#map-option)
     */
    @Prop()
    public mapOptions: MapOptions;

    @Prop()
    public coverage: Coverage;

    // markerService: MarkerService
    /**
     * Bounds for the map
     */
    @Prop({ default: null })
    public fitBounds: LatLngBoundsExpression;

    /**
     * Describes the the zoom control options (see: https://leafletjs.com/reference-1.3.4.html#control-zoom)
     */
    @Prop()
    public zoomControlOptions: Control.ZoomOptions;

    @Prop()
    public baseMaps: LayerMap;

    get label(): string {
        return this.validBoundingBox ? '  valid' : 'invalid';
    }

    get validBoundingBox(): boolean {
        let isValidNumber =
            (typeof this.coverage.x_min === 'number' || !isNaN(Number(this.coverage.x_min))) &&
            (typeof this.coverage.y_min === 'number' || !isNaN(Number(this.coverage.y_min))) &&
            (typeof this.coverage.x_max === 'number' || !isNaN(Number(this.coverage.x_max))) &&
            (typeof this.coverage.y_max === 'number' || !isNaN(Number(this.coverage.y_max)));

        let isBoundValid = true;
        if (isValidNumber) {
            let _southWest: LatLng = new LatLng(this.coverage.y_min, this.coverage.x_min);
            let _northEast: LatLng = new LatLng(this.coverage.y_max, this.coverage.x_max);
            const bounds = new LatLngBounds(this.southWest, this.northEast);
            if (!bounds.isValid() || !(_southWest.lat < _northEast.lat && _southWest.lng < _northEast.lng)) {
                // this.draw.removeShape();
                // Notification.showTemporary('Bounds are not valid.');
                isBoundValid = false;
            }
        }
        return isValidNumber && isBoundValid;
    }

    @Ref('zoom') private zoom: ZoomControlComponent;
    @Ref('draw') private draw: DrawControlComponent;

    // services:
    mapService = MapService();

    mdiMapCheckOutline = mdiMapCheckOutline;
    southWest: LatLng;
    northEast: LatLng;

    /**
     * Informs when initialization is done with map id.
     */
    public onMapInitializedEvent: EventEmitter<string> = new EventEmitter<string>();

    public map!: Map;
    // protected drawnItems!: FeatureGroup<any>;

    validateBoundingBox() {
        if (this.validBoundingBox == false) {
            this.draw.removeShape();
            Notification.showError('Bounds are not valid.');
            return;
        }
        this.map.control && this.map.control.disable();
        var _this = this;
        // // _this.locationErrors.length = 0;
        // this.drawnItems.clearLayers();
        // //var xmin = document.getElementById("xmin").value;
        // var xmin = (<HTMLInputElement>document.getElementById("xmin")).value;
        // // var ymin = document.getElementById("ymin").value;
        // var ymin = (<HTMLInputElement>document.getElementById("ymin")).value;
        // //var xmax = document.getElementById("xmax").value;
        // var xmax = (<HTMLInputElement>document.getElementById("xmax")).value;
        // //var ymax = document.getElementById("ymax").value;
        // var ymax = (<HTMLInputElement>document.getElementById("ymax")).value;
        // var bounds = [[ymin, xmin], [ymax, xmax]];

        // let _southWest: LatLng;
        // let _northEast: LatLng;
        // if (this.coverage.x_min && this.coverage.y_min) {
        let _southWest: LatLng = new LatLng(this.coverage.y_min, this.coverage.x_min);
        // }
        // if (this.coverage.x_max && this.coverage.y_max) {
        let _northEast: LatLng = new LatLng(this.coverage.y_max, this.coverage.x_max);
        // }
        const bounds = new LatLngBounds(this.southWest, this.northEast);
        if (!bounds.isValid() || !(_southWest.lat < _northEast.lat && _southWest.lng < _northEast.lng)) {
            this.draw.removeShape();
            Notification.showTemporary('Bounds are not valid.');
        } else {
            // this.draw.drawShape(_southWest, _northEast);
            try {
                this.draw.drawShape(_southWest, _northEast);
                _this.map.fitBounds(bounds);

                // var boundingBox = L.rectangle(bounds, { color: "#005F6A", weight: 1 });
                // // this.geolocation.xmin = xmin;
                // // this.geolocation.ymin = ymin;
                // // this.geolocation.xmax = xmax;
                // // this.geolocation.ymax = ymax;

                // _this.drawnItems.addLayer(boundingBox);
                // _this.map.fitBounds(bounds);
                // this.options.message = "valid bounding box";
                // this.$toast.success("valid bounding box", this.options);
                Notification.showSuccess('valid bounding box');
            } catch (err) {
                // this.options.message = e.message;
                // // _this.errors.push(e);
                // this.$toast.error(e.message, this.options);
                Notification.showTemporary('An error occurred while drawing bounding box');
                // generatingCodes.value = false;
                throw err;
            }
        }
    }

    mounted(): void {
        this.initMap();
    }

    unmounted() {
        this.map.off('zoomend zoomlevelschange');
    }

    // @Emit(this.onMapInitializedEvent)
    protected initMap(): void {
        // let map: Map = (this.map = this.mapService.getMap(this.mapId));

        let map: Map = (this.map = new Map(this.mapId, this.mapOptions));
        this.mapService.setMap(this.mapId, map);
        map.scrollWheelZoom.disable();

        // return this.mapId;
        //    this.$emit("onMapInitializedEvent", this.mapId);
        this.onMapInitializedEvent.emit(this.mapId);
        this.addBaseMap();

        const attributionControl = new Attribution().addTo(this.map);
        attributionControl.setPrefix(false);

        map.on(
            'Draw.Event.CREATED',
            function (event) {
                // drawnItems.clearLayers();
                // var type = event.type;
                var layer = event.layer;

                // if (type === "rectancle") {
                // layer.bindPopup("A popup!" + layer.getBounds().toBBoxString());
                var bounds = layer.getBounds();
                this.coverage.x_min = bounds.getSouthWest().lng;
                this.coverage.y_min = bounds.getSouthWest().lat;
                // console.log(this.geolocation.xmin);
                this.coverage.x_max = bounds.getNorthEast().lng;
                this.coverage.y_max = bounds.getNorthEast().lat;
                // }

                // drawnItems.addLayer(layer);
            },
            this,
        );

        // Initialise the FeatureGroup to store editable layers
        // let drawnItems = (this.drawnItems = new FeatureGroup());
        // map.addLayer(drawnItems);

        this.map.on('zoomend zoomlevelschange', this.zoom.updateDisabled, this.zoom);

        // if (this.fitBounds) {
        //     this.map.fitBounds(this.fitBounds);
        // }
        if (this.coverage.x_min && this.coverage.y_min) {
            this.southWest = new LatLng(this.coverage.y_min, this.coverage.x_min);
        } else {
            this.southWest = new LatLng(46.5, 9.9);
        }
        if (this.coverage.x_max && this.coverage.y_max) {
            this.northEast = new LatLng(this.coverage.y_max, this.coverage.x_max);
        } else {
            this.northEast = new LatLng(48.9, 16.9);
        } // this.northEast = toLatLng(48.9, 16.9);
        const bounds = new LatLngBounds(this.southWest, this.northEast);
        map.fitBounds(bounds);

        if (this.coverage.x_min && this.coverage.x_max && this.coverage.y_min && this.coverage.y_max) {
            let _southWest: LatLng;
            let _northEast: LatLng;
            if (this.coverage.x_min && this.coverage.y_min) {
                _southWest = new LatLng(this.coverage.y_min, this.coverage.x_min);
            }
            if (this.coverage.x_max && this.coverage.y_max) {
                _northEast = new LatLng(this.coverage.y_max, this.coverage.x_max);
            }
            this.draw.drawShape(_southWest, _northEast);
        }
    }

    private addBaseMap(layerOptions?: LayerOptions): void {
        if (this.map) {
            if (!this.baseMaps || this.baseMaps.size === 0) {
                // let bmapgrau = tileLayer('https://{s}.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png', {
                //         subdomains: ['maps', 'maps1', 'maps2', 'maps3', 'maps4'],
                //         attribution: 'Datenquelle: <a href="http://www.basemap.at/">basemap.at</a>',
                // });
                let osmGgray = tileLayerWMS('https://ows.terrestris.de/osm-gray/service', {
                    format: 'image/png',
                    attribution: DEFAULT_BASE_LAYER_ATTRIBUTION,
                    layers: 'OSM-WMS',
                });
                layerOptions = {
                    label: DEFAULT_BASE_LAYER_NAME,
                    visible: true,
                    layer: osmGgray,
                };
                layerOptions.layer.addTo(this.map);
            }
        }
    }
}
</script>

<style scoped lang="css">
/* .leaflet-container {
    height: 600px;
    width: 100%;
    background-color: transparent;
    outline-offset: 1px;
} */
.leaflet-container {
    height: 600px;
    width: 100%;
    background: none;
}

.gba-control-validate {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    cursor: pointer;
    border-radius: 4px;
    position: absolute;
    left: 10px;
    top: 150px;
    z-index: 999;
}

.btn-group-vertical button {
    display: block;

    margin-left: 0;
    margin-top: 0.5em;
}

/* .leaflet-pane  {
    z-index: 30;
} */
</style>
