<script setup lang="ts">
import { AirTrafficLayer } from '@/services/adsb.ts'
import { AISLayer } from '@/services/ais.ts'
import { api } from '@/services/api.ts'
import { RangeLayer } from '@/services/range.ts'
import VectorTileLayer from 'ol/layer/VectorTile'
import { 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 { defaults as defaultInteractions } from 'ol/interaction'
import { fromLonLat, toLonLat } from 'ol/proj'
import { Style, Fill, Stroke, Circle as CircleStyle } from 'ol/style'
import { applyStyle } from 'ol-mapbox-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 showWind = ref(false)
const windSrc = ref('')

const OVERLAYS = [
	{ id: 'rain', label: 'Rain', icon: '🌧️' },
	{ id: 'wind', label: 'Wind', icon: '💨' },
]

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
let aisLayer: AISLayer
let range: RangeLayer

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)
}

function showWindOverlay() {
	syncWindSrc()
	showWind.value = true
	map.getInteractions().forEach(i => i.setActive(false))
}

function hideWindOverlay() {
	showWind.value = false
	map.getInteractions().forEach(i => i.setActive(true))
}

async function fetchRadarUrl(): Promise<string | null> {
	try {
		const res = await fetch('https://api.rainviewer.com/public/weather-maps.json')
		const data = await res.json()
		const past = data.radar?.past ?? []
		const latest = past[past.length - 1]
		if (!latest) return null
		return `https://tilecache.rainviewer.com${latest.path}/256/{z}/{x}/{y}/2/1_1.png`
	} catch {
		return null
	}
}

function buildRainLayer(url: string): TileLayer<XYZ> {
	return new TileLayer({
		source: new XYZ({
			url,
			maxZoom: 7,
			tileLoadFunction: (tile: any, src: string) => {
				const img = tile.getImage()
				img.onerror = () => tile.setState(3)
				img.src = src
			},
		}),
		opacity: 0.2,
		zIndex: 5,
	})
}

async function refreshRain() {
	const url = await fetchRadarUrl()
	if (!url) return

	if (overlayLayers['rain']) map.removeLayer(overlayLayers['rain'])
	if (!activeOverlays.value.has('rain')) return

	const layer = buildRainLayer(url)
	overlayLayers['rain'] = layer
	map.addLayer(layer)
}

function toggleAT() {
	if (atActive.value) {
		aisLayer.hide()
		airTraffic.hide()
		range.hide()
	} else {
		aisLayer.show()
		airTraffic.show()
		range.show()
	}
	atActive.value = !atActive.value
}

function toggleOverlay(id: string) {
	if (id === 'wind') {
		if (activeOverlays.value.has('wind')) {
			activeOverlays.value.delete('wind')
			hideWindOverlay()
		} else {
			activeOverlays.value.add('wind')
			showWindOverlay()
		}
		return
	}

	if (id === 'rain') {
		if (activeOverlays.value.has('rain')) {
			activeOverlays.value.delete('rain')
			if (overlayLayers['rain']) { map.removeLayer(overlayLayers['rain']); delete overlayLayers['rain'] }
		} else {
			activeOverlays.value.add('rain')
			refreshRain()
		}
		return
	}
}

function buildBaseLayer(dark: boolean) {
	const layer = new VectorTileLayer({ declutter: true })
	applyStyle(layer, dark ? '/dark-theme.json' : '/light-theme.json')
	return layer
}

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 () => {
	const position = await api.position()
	current.value = {
		latitude: position?.latitude || 0,
		longitude: position?.longitude || 0,
	}

	stationLayer = buildStationLayer(current.value.latitude, current.value.longitude, props.dark)

	map = new Map({
		target: mapEl.value!,
		layers: [buildBaseLayer(props.dark), stationLayer],
		interactions: defaultInteractions({ altShiftDragRotate: false, pinchRotate: false }),
		view: new View({ center: fromLonLat([current.value.longitude, current.value.latitude]), zoom: 8, maxZoom: 13 }),
		controls: [],
	})

	aisLayer = new AISLayer(map)
	aisLayer.show()
	airTraffic = new AirTrafficLayer(map)
	airTraffic.show()
	range = new RangeLayer(map)
	range.show()

	refreshRain()
	radarInterval = setInterval(refreshRain, 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);
}

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

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

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

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

		<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>

		<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>
