<script setup lang="ts">
import { onMounted, onUnmounted, ref, Ref, defineProps, computed } from 'vue';
import SectionMain from '@/Components/SectionMain.vue';
import { Map } from 'leaflet/src/map/index';
import { Rectangle } from 'leaflet';
import { canvas } from 'leaflet/src/layer/vector/Canvas';
import { svg } from 'leaflet/src/layer/vector/SVG';
import axios from 'axios';
import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds';
import { tileLayerWMS } from 'leaflet/src/layer/tile/TileLayer.WMS';
import { Attribution } from 'leaflet/src/control/Control.Attribution';
import DrawControlComponent from '@/Components/Map/draw.component.vue';
import ZoomControlComponent from '@/Components/Map/zoom.component.vue';
import { MapService } from '@/Stores/map.service';
import { LayerGroup } from 'leaflet/src/layer/LayerGroup';
import { OpensearchDocument } from '@/Dataset';

Map.include({
    getRenderer: function (layer) {
        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) {
        return (this.options.preferCanvas && canvas(options)) || svg(options);
    },
});

const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
const DEFAULT_BASE_LAYER_ATTRIBUTION = '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors';
const OPENSEARCH_HOST = 'https://catalog.geosphere.at';

let map: Map;

const props = defineProps({
    checkable: Boolean,
    datasets: {
        type: Array<OpensearchDocument>,
        default: () => [],
    },
    mapId: {
        type: String,
        default: 'map',
    },
    mapOptions: {
        type: Object,
        default: () => ({
            center: [48.208174, 16.373819],
            zoom: 3,
            zoomControl: false,
            attributionControl: false,
        }),
    },
});

const items = computed({
    get() {
        return props.datasets;
    },
    set(value) {
        props.datasets.length = 0;
        props.datasets.push(...value);
    },
});

const fitBounds: LatLngBoundsExpression = [
    [46.4318173285, 9.47996951665],
    [49.0390742051, 16.9796667823],
];

const drawControl: Ref<DrawControlComponent | null> = ref(null);
const southWest = ref(null);
const northEast = ref(null);
const mapService = MapService();
const isLoading = ref(false);

const filterLayerGroup = new LayerGroup();

onMounted(() => {
    initMap();
});

onUnmounted(() => {
    map.off('zoomend zoomlevelschange');
});

const initMap = async () => {
    map = new Map('map', props.mapOptions);
    mapService.setMap(props.mapId, map);
    map.scrollWheelZoom.disable();
    map.fitBounds(fitBounds);
    drawControl.value?.toggleDraw();

    map.addLayer(filterLayerGroup);

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

    let osmGgray = tileLayerWMS('https://ows.terrestris.de/osm-gray/service', {
        format: 'image/png',
        attribution: DEFAULT_BASE_LAYER_ATTRIBUTION,
        layers: 'OSM-WMS',
    });

    let layerOptions = {
        label: DEFAULT_BASE_LAYER_NAME,
        visible: true,
        layer: osmGgray,
    };
    layerOptions.layer.addTo(map);

    map.on('Draw.Event.CREATED', handleDrawEventCreated);
};

const handleDrawEventCreated = async (event) => {
    isLoading.value = true;
    filterLayerGroup.clearLayers();
    items.value = [];

    let layer = event.layer;
    let bounds = layer.getBounds();

    try {
        let response = await axios({
            method: 'POST',
            url: OPENSEARCH_HOST + '/tethys-records/_search',
            headers: { 'Content-Type': 'application/json' },
            data: {
                size: 1000,
                query: {
                    bool: {
                        must: {
                            match_all: {},
                        },
                        filter: {
                            geo_shape: {
                                geo_location: {
                                    shape: {
                                        type: 'envelope',
                                        coordinates: [
                                            [bounds.getSouthWest().lng, bounds.getNorthEast().lat],
                                            [bounds.getNorthEast().lng, bounds.getSouthWest().lat],
                                        ],
                                    },
                                    relation: 'within',
                                },
                            },
                        },
                    },
                },
            },
        });

        response.data.hits.hits.forEach((hit) => {
            let xMin = hit._source.bbox_xmin;
            let xMax = hit._source.bbox_xmax;
            let yMin = hit._source.bbox_ymin;
            let yMax = hit._source.bbox_ymax;
            var bbox: LatLngBoundsExpression = [
                [yMin, xMin],
                [yMax, xMax],
            ];

            let rect = new Rectangle(bbox, {
                color: '#65DC21',
                weight: 2,
                fillColor: '#65DC21',
                fillOpacity: 0.2,
                className: 'animated-rectangle',
            });
            filterLayerGroup.addLayer(rect);
            items.value.push(hit._source);
        });
    } catch (error) {
        console.error(error);
    } finally {
        isLoading.value = false;
    }
};
</script>

<template>
    <SectionMain>
        <div class="map-container-wrapper">
            <!-- Loading Overlay -->
            <div v-if="isLoading" class="loading-overlay">
                <div class="loading-spinner"></div>
                <p class="loading-text">Searching datasets...</p>
            </div>

            <!-- Map Instructions Banner -->
            <div class="map-instructions">
                <svg class="instruction-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                    <circle cx="12" cy="12" r="10" />
                    <path d="M12 16v-4M12 8h.01" />
                </svg>
                <p class="instruction-text">
                    <strong>Tip:</strong> Use the drawing tool to select an area on the map and discover datasets
                </p>
            </div>

            <div id="map" class="map-container">
                <ZoomControlComponent ref="zoomControl" :mapId="mapId"></ZoomControlComponent>
                <DrawControlComponent ref="drawControl" :preserve="false" :mapId="mapId" :southWest="southWest" :northEast="northEast">
                </DrawControlComponent>
            </div>
        </div>
    </SectionMain>
</template>

<style scoped>
.map-container-wrapper {
    position: relative;
    border-radius: 1rem;
    overflow: hidden;
    background: white;
    box-shadow:
        0 4px 6px -1px rgba(0, 0, 0, 0.1),
        0 2px 4px -1px rgba(0, 0, 0, 0.06);
}

.dark .map-container-wrapper {
    background: #1f2937;
}

/* Map Instructions Banner */
.map-instructions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.5rem;
    background: linear-gradient(135deg, rgba(101, 220, 33, 0.1) 0%, rgba(53, 124, 6, 0.1) 100%);
    border-bottom: 2px solid #e5e7eb;
}

.dark .map-instructions {
    background: linear-gradient(135deg, rgba(101, 220, 33, 0.2) 0%, rgba(53, 124, 6, 0.2) 100%);
    border-bottom-color: #374151;
}

.instruction-icon {
    width: 1.5rem;
    height: 1.5rem;
    color: #65dc21;
    flex-shrink: 0;
}

.instruction-text {
    font-size: 0.875rem;
    color: #4b5563;
    margin: 0;
}

.dark .instruction-text {
    color: #d1d5db;
}

.instruction-text strong {
    color: #65dc21;
    font-weight: 600;
}

/* Loading Overlay */
.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(255, 255, 255, 0.95);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    backdrop-filter: blur(4px);
}

.dark .loading-overlay {
    background: rgba(31, 41, 55, 0.95);
}

.loading-spinner {
    width: 3rem;
    height: 3rem;
    border: 4px solid #e5e7eb;
    border-top-color: #65dc21;
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

.dark .loading-spinner {
    border-color: #374151;
    border-top-color: #65dc21;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.loading-text {
    margin-top: 1rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: #65dc21;
}

/* Map Container */
.map-container {
    position: relative;
    height: 600px;
    width: 100%;
    background: #f9fafb;
}

.dark .map-container {
    background: #111827;
}

/* Leaflet Overrides */
:deep(.leaflet-container) {
    height: 600px;
    width: 100%;
    background: transparent;
    font-family: inherit;
}

:deep(.leaflet-container .leaflet-pane) {
    z-index: 30 !important;
}

/* Enhanced Rectangle Styling */
:deep(.animated-rectangle) {
    animation: pulseRectangle 2s ease-in-out infinite;
}

@keyframes pulseRectangle {
    0%,
    100% {
        opacity: 0.6;
    }
    50% {
        opacity: 1;
    }
}

/* Control Enhancements */
:deep(.leaflet-control) {
    border-radius: 0.5rem;
    box-shadow:
        0 4px 6px -1px rgba(0, 0, 0, 0.1),
        0 2px 4px -1px rgba(0, 0, 0, 0.06);
    border: none;
}

:deep(.leaflet-bar a) {
    border-radius: 0.5rem;
    transition: all 0.2s ease;
}

:deep(.leaflet-bar a:hover) {
    background: #65dc21;
    color: white;
}

:deep(.leaflet-draw-toolbar a) {
    background: white;
    transition: all 0.2s ease;
}

.dark :deep(.leaflet-draw-toolbar a) {
    background: #374151;
    color: #d1d5db;
}

:deep(.leaflet-draw-toolbar a:hover) {
    background: #65dc21;
}

/* Popup Enhancements */
:deep(.leaflet-popup-content-wrapper) {
    border-radius: 0.75rem;
    box-shadow:
        0 10px 15px -3px rgba(0, 0, 0, 0.1),
        0 4px 6px -2px rgba(0, 0, 0, 0.05);
}

:deep(.leaflet-popup-tip) {
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Responsive Design */
@media (max-width: 768px) {
    .map-container {
        height: 400px;
    }

    .map-instructions {
        padding: 0.75rem 1rem;
    }

    .instruction-text {
        font-size: 0.8125rem;
    }
}

@media (max-width: 640px) {
    .map-container {
        height: 350px;
    }
}
</style>
