<script setup lang="ts">
import { AirTrafficLayer } from '@/services/airtraffic.ts'
import {api} from '@/services/api.ts';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import CircleGeom from 'ol/geom/Circle'
import { fromLonLat, toLonLat } from 'ol/proj'
import { Style, Fill, Stroke, Circle as CircleStyle } from 'ol/style'
import 'ol/ol.css'

const current = ref({latitude: 0, longitude: 0});
const props  = defineProps<{ dark: boolean }>()
const mapEl  = ref<HTMLDivElement>()
const showOverlays = ref(false)
const atActive = ref(true)

const NM = 1852

const radarFrames = ref<{ path: string; time: number }[]>([])
const radarFrameIndex = ref(0)
const radarPath = computed(() => radarFrames.value[radarFrameIndex.value]?.path ?? '')
const nowcastStartIndex = ref(0)

const showWind = ref(false)
const windSrc = ref('')

const OVERLAYS = [
	{ id: 'rain', label: 'Rain', icon: '🌧️', url: () => `https://tilecache.rainviewer.com${radarPath.value}/256/{z}/{x}/{y}/2/1_1.png` },
	{ id: 'wind', label: 'Wind', icon: '💨',  url: () => '' },
]

const activeOverlays = ref<Set<string>>(new Set(['rain']))
const overlayLayers: { [key: string]: any } = {}

let map: Map
let stationLayer: VectorLayer<VectorSource>
let radarInterval: ReturnType<typeof setInterval>
let airTraffic: AirTrafficLayer

const hourTickIndices = computed(() => {
	const indices: number[] = []
	let lastHour = -1
	radarFrames.value.forEach((f, i) => {
		const h = new Date(f.time * 1000).getHours()
		if (h !== lastHour) { indices.push(i); lastHour = h }
	})
	return indices
})

function buildWindSrc(lat: number, lon: number, zoom: number) {
	return `https://embed.windy.com/embed2.html?lat=${lat.toFixed(4)}&lon=${lon.toFixed(4)}&detailLat=${lat.toFixed(4)}&detailLon=${lon.toFixed(4)}&zoom=${Math.round(zoom)}&level=surface&overlay=wind&product=ecmwf&menu=&message=&marker=&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=kt&metricTemp=%C2%B0C&radarRange=-1`
}

function syncWindSrc() {
	const view   = map.getView()
	const center: any = toLonLat(view.getCenter()!)
	windSrc.value = buildWindSrc(center[1], center[0], view.getZoom() ?? 8)
}

async function fetchRadarFrames() {
	const res  = await fetch('https://api.rainviewer.com/public/weather-maps.json')
	const data = await res.json()
	const past    = data.radar.past    ?? []
	const nowcast = data.radar.nowcast ?? []
	radarFrames.value = [...past, ...nowcast]
	nowcastStartIndex.value = past.length
}

function buildRainSource(url: string): XYZ {
	return new XYZ({
		url,
		attributions: '',
		maxZoom: 7,
		tileLoadFunction: (tile: any, src: string) => {
			const img = tile.getImage()
			img.onerror = () => tile.setState(3)
			img.src = src
		},
	})
}

function seekRadar(index: number) {
	radarFrameIndex.value = index
	const layer = overlayLayers['rain']
	if (layer) {
		layer.setSource(buildRainSource(OVERLAYS.find(o => o.id === 'rain')!.url()))
	}
}

function onSliderInput(e: Event) {
	seekRadar(Number((e.target as HTMLInputElement).value))
}

function frameLabel(frame: { time: number }) {
	return new Date(frame.time * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
}

function hourLabel(frame: { time: number }) {
	return new Date(frame.time * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })
}

function tickPercent(index: number) {
	return (index / (radarFrames.value.length - 1)) * 100
}

function toggleAT() {
	atActive.value ? airTraffic.hide() : airTraffic.show()
	atActive.value = !atActive.value
}

function toggleOverlay(id: string) {
	if (id === 'wind') {
		if (activeOverlays.value.has('wind')) {
			activeOverlays.value.delete('wind')
			showWind.value = false
		} else {
			activeOverlays.value.add('wind')
			syncWindSrc()
			showWind.value = true
		}
		return
	}

	if (activeOverlays.value.has(id)) {
		activeOverlays.value.delete(id)
		const layer = overlayLayers[id]
		if (layer) { map.removeLayer(layer); delete overlayLayers[id] }
	} else {
		activeOverlays.value.add(id)
		const layer = buildOverlayLayer(id)
		overlayLayers[id] = layer
		map.addLayer(layer)
	}
}

function buildBaseLayer(dark: boolean) {
	return new TileLayer({
		source: new XYZ({
			url: dark
				? 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}.png'
				: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}.png',
			attributions: '© Stadia Maps © OpenMapTiles © OpenStreetMap',
		}),
	})
}

function buildOverlayLayer(id: string): TileLayer<XYZ> {
	const def = OVERLAYS.find(o => o.id === id)!
	return new TileLayer({
		source: buildRainSource(def.url()),
		opacity: 0.2,
		zIndex:  5,
	})
}

function buildStationLayer(lat: number, lon: number, dark: boolean): VectorLayer<VectorSource> {
	const center     = fromLonLat([lon, lat])
	const source     = new VectorSource()
	const ringStroke = dark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.35)'

	for (const nm of [50, 100, 150, 200]) {
		const ring = new Feature(new CircleGeom(center, nm * NM))
		ring.setStyle(new Style({
			stroke: new Stroke({ color: ringStroke, width: 1, lineDash: [6, 4] }),
			fill:   new Fill({ color: 'transparent' }),
		}))
		source.addFeature(ring)
	}

	const dot = new Feature(new Point(center))
	dot.setStyle(new Style({
		image: new CircleStyle({
			radius: 7,
			fill:   new Fill({ color: dark ? '#ffffff' : '#000000' }),
			stroke: new Stroke({ color: dark ? '#000000' : '#ffffff', width: 2 }),
		}),
	}))
	source.addFeature(dot)

	return new VectorLayer({ source, zIndex: 20 })
}

onMounted(async () => {
	await fetchRadarFrames()
	radarFrameIndex.value = nowcastStartIndex.value - 1

	const position = await api.position();

	const lat = position?.latitude || 0
	const lon = position?.longitude || 0

	stationLayer = buildStationLayer(lat, lon, props.dark)

	map = new Map({
		target:   mapEl.value!,
		layers:   [buildBaseLayer(props.dark), stationLayer],
		view:     new View({ center: fromLonLat([lon, lat]), zoom: 8, maxZoom: 13 }),
		controls: [],
	})

	airTraffic = new AirTrafficLayer(map)
	airTraffic.show()

	for (const id of activeOverlays.value) {
		if (id === 'wind') continue
		const layer = buildOverlayLayer(id)
		overlayLayers[id] = layer
		map.addLayer(layer)
	}

	map.on('moveend', () => {
		if (showWind.value) syncWindSrc()
	})

	radarInterval = setInterval(async () => {
		await fetchRadarFrames()
		radarFrameIndex.value = nowcastStartIndex.value - 1
		seekRadar(radarFrameIndex.value)
	}, 5 * 60 * 1000)
})

onUnmounted(() => {
	clearInterval(radarInterval)
	airTraffic.hide()
})

watch(() => props.dark, dark => {
	map.getLayers().setAt(0, buildBaseLayer(dark))
	map.removeLayer(stationLayer)
	const lat = (current.value.latitude as number) || 0
	const lon = (current.value.longitude as number) || 0
	stationLayer = buildStationLayer(lat, lon, dark)
	map.addLayer(stationLayer)
})
</script>

<style scoped lang="scss">
.map-wrap {
	position: relative;
	width: 100%;
	height: 100%;
	border-radius: 12px;
	overflow: hidden;
}

.map-el {
	width: 100%;
	height: 100%;
}

.wind-iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: none;
	z-index: 10;
}

.overlay-btn {
	display: flex;
	align-items: center;
	gap: 4px;
	padding: 6px 12px;
	border-radius: 99px;
	border: 1.5px solid var(--border);
	background: transparent;
	color: var(--text);
	font-size: 13px;
	cursor: pointer;
	transition: all 0.15s;
	white-space: nowrap;

	&.active {
		background: var(--accent);
		border-color: var(--accent);
		color: #fff;
	}

	&:hover:not(.active) { background: var(--hover); }
}

.overlay-toggles {
	position: absolute;
	bottom: 16px;
	left: 50%;
	transform: translateX(-50%);
	display: flex;
	gap: 8px;
	z-index: 100;
	background: var(--surface);
	border-radius: 99px;
	padding: 6px 10px;
	box-shadow: 0 2px 12px rgba(0,0,0,0.2);
	backdrop-filter: blur(8px);
}

.layers-menu {
	position: absolute;
	bottom: 16px;
	right: 10px;
	z-index: 100;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 8px;
}

.layers-btn {
	padding: 8px 14px;
	border-radius: 99px;
	border: 1.5px solid var(--border);
	background: var(--surface);
	color: var(--text);
	font-size: 13px;
	cursor: pointer;
	backdrop-filter: blur(8px);
	box-shadow: 0 2px 12px rgba(0,0,0,0.2);
}

.layers-dropdown {
	display: flex;
	flex-direction: column;
	gap: 6px;
	background: var(--surface);
	border-radius: 12px;
	padding: 8px;
	box-shadow: 0 2px 12px rgba(0,0,0,0.2);
	backdrop-filter: blur(8px);
}

.radar-timeline {
	position: absolute;
	bottom: 72px;
	left: 50%;
	transform: translateX(-50%);
	z-index: 100;
	display: flex;
	align-items: center;
	gap: 10px;
	background: var(--surface);
	border-radius: 16px;
	padding: 8px 16px;
	box-shadow: 0 2px 12px rgba(0,0,0,0.2);
	backdrop-filter: blur(8px);
	width: min(600px, calc(100vw - 32px));
}

.slider-wrap {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.slider-ticks {
	position: relative;
	height: 16px;
}

.tick {
	position: absolute;
	transform: translateX(-50%);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;

	&__line {
		width: 1px;
		height: 5px;
		background: var(--border);
	}

	&__label {
		font-size: 9px;
		color: var(--text-muted, #888);
		white-space: nowrap;
	}

	&.nowcast &__line  { background: #6ab4ff; }
	&.nowcast &__label { color: #6ab4ff; }
}

input[type='range'] {
	width: 100%;
	accent-color: var(--accent);
	cursor: pointer;
}

.timeline-label {
	font-size: 12px;
	color: var(--text);
	min-width: 42px;
	text-align: right;
	flex-shrink: 0;
}

.desktop { display: flex; }
.mobile  { display: none; }

@media (max-width: 768px) {
	.desktop { display: none; }
	.mobile  { display: flex; }
	.radar-timeline { bottom: 10px; }
	.overlay-toggles { bottom: 10px; }
	.layers-menu { bottom: 10px; }
}
</style>

<template>
	<div class="map-wrap">
		<div ref="mapEl" class="map-el" />

		<!-- Windy animated wind iframe -->
		<iframe
			v-if="showWind"
			class="wind-iframe"
			:src="windSrc"
			frameborder="0"
			allowfullscreen
		/>

		<!-- Desktop toggles -->
		<div class="overlay-toggles desktop">
			<button class="overlay-btn" :class="{ active: atActive }" @click="toggleAT">
				✈️ Traffic
			</button>
			<button
				v-for="o in OVERLAYS" :key="o.id"
				class="overlay-btn"
				:class="{ active: activeOverlays.has(o.id) }"
				@click="toggleOverlay(o.id)"
			>
				{{ o.icon }} {{ o.label }}
			</button>
		</div>

		<!-- Mobile layers button + dropdown -->
		<div class="layers-menu mobile">
			<button class="layers-btn" @click="showOverlays = !showOverlays">
				⚙️ Layers
			</button>
			<div v-if="showOverlays" class="layers-dropdown">
				<button class="overlay-btn" :class="{ active: atActive }" @click="toggleAT">
					✈️ Traffic
				</button>
				<button
					v-for="o in OVERLAYS" :key="o.id"
					class="overlay-btn"
					:class="{ active: activeOverlays.has(o.id) }"
					@click="toggleOverlay(o.id)"
				>
					{{ o.icon }} {{ o.label }}
				</button>
			</div>
		</div>
	</div>
</template>
