<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'

const BASE_SPEED_UNITS = {
	knots: { label: 'KTS', convert: (v: number) => Math.round(v) },
	kph:   { label: 'KPH', convert: (v: number) => Math.round(v * 1.852) },
	mph:   { label: 'MPH', convert: (v: number) => Math.round(v * 1.15078) },
}
const BASE_ALTITUDE_UNITS = {
	meters: { label: 'M',  convert: (v: number) => Math.round(v * 0.3048) },
	feet:   { label: 'FT', convert: (v: number) => v },
}
const BASE_VERTICAL_UNITS = {
	mps: { label: 'M/S',  convert: (v: number) => Math.round(v * 0.3048) },
	fps: { label: 'FT/S', convert: (v: number) => v },
}

const UNIT_KEY = 'at_units'
function loadUnits() {
	const s = localStorage.getItem(UNIT_KEY)
	return s ? JSON.parse(s) : { speed: 'knots', altitude: 'meters', vertical: 'mps' }
}

const props = defineProps<{ plane: any; position: { x: number; y: number } }>()
const emit  = defineEmits<{ (e: 'close'): void; (e: 'bringToFront'): void }>()

// ── Units ─────────────────────────────────────────────────────────────────────
const prefs = ref(loadUnits())
function saveAndSet(p: any) {
	prefs.value = { ...p }
	localStorage.setItem(UNIT_KEY, JSON.stringify(prefs.value))
}
function cycleSpeed()    { const keys = Object.keys(BASE_SPEED_UNITS);    const p = loadUnits(); p.speed    = keys[(keys.indexOf(p.speed)    + 1) % keys.length]; saveAndSet(p) }
function cycleAltitude() { const keys = Object.keys(BASE_ALTITUDE_UNITS); const p = loadUnits(); p.altitude = keys[(keys.indexOf(p.altitude) + 1) % keys.length]; p.vertical = p.altitude === 'meters' ? 'mps' : 'fps'; saveAndSet(p) }
function cycleVertical() { const keys = Object.keys(BASE_VERTICAL_UNITS); const p = loadUnits(); p.vertical = keys[(keys.indexOf(p.vertical) + 1) % keys.length]; p.altitude = p.vertical === 'mps' ? 'meters' : 'feet'; saveAndSet(p) }

const speed    = computed(() => BASE_SPEED_UNITS[prefs.value.speed       as keyof typeof BASE_SPEED_UNITS])
const altitude = computed(() => BASE_ALTITUDE_UNITS[prefs.value.altitude as keyof typeof BASE_ALTITUDE_UNITS])
const vertical = computed(() => BASE_VERTICAL_UNITS[prefs.value.vertical as keyof typeof BASE_VERTICAL_UNITS])

// ── Plane data ────────────────────────────────────────────────────────────────
const callsign    = computed(() => props.plane.name?.trim() || props.plane.flight?.trim())
const altitudeVal = computed(() => props.plane.alt_baro ?? props.plane.alt_geom ?? 0)
const speedVal    = computed(() => speed.value.convert(props.plane.speed || props.plane.gs || 0))
const altVal      = computed(() => props.plane.landed ? 'LANDED' : altitude.value.convert(altitudeVal.value))
const altUnit     = computed(() => props.plane.landed ? '' : altitude.value.label)
const climbVal    = computed(() => { const v = vertical.value.convert(props.plane.climb || props.plane.baro_rate || 0); return v >= 0 ? `+${v}` : String(v) })
const description = computed(() => props.plane.desc || [props.plane.manufacturer, props.plane.model].filter(Boolean).join(' ') || '')
const operator    = computed(() => props.plane.operator || props.plane.owner || '')

// ── Drag ──────────────────────────────────────────────────────────────────────
const pos            = ref({ ...props.position })
const isDragging     = ref(false)
const dragStart      = ref({ mx: 0, my: 0, ex: 0, ey: 0 })
const longPressTimer = ref<number | null>(null)
const header         = ref<HTMLElement | null>(null)

function onMouseDown(e: MouseEvent) {
	if ((e.target as HTMLElement).classList.contains('ap-close')) return
	emit('bringToFront')
	isDragging.value  = true
	dragStart.value   = { mx: e.clientX, my: e.clientY, ex: pos.value.x, ey: pos.value.y }
	e.preventDefault()
}
function onMouseMove(e: MouseEvent) {
	if (!isDragging.value) return
	pos.value.x = dragStart.value.ex + (e.clientX - dragStart.value.mx)
	pos.value.y = dragStart.value.ey + (e.clientY - dragStart.value.my)
}
function onMouseUp() { isDragging.value = false }

function onTouchStart(e: TouchEvent) {
	if ((e.target as HTMLElement).classList.contains('ap-close')) return
	const touch = e.touches[0]
	const sx = touch.clientX, sy = touch.clientY
	longPressTimer.value = window.setTimeout(() => {
		emit('bringToFront')
		isDragging.value = true
		dragStart.value  = { mx: sx, my: sy, ex: pos.value.x, ey: pos.value.y }
		if (header.value) header.value.style.opacity = '0.8'
	}, 500)
}
function onTouchMove(e: TouchEvent) {
	if (!isDragging.value) return
	const touch = e.touches[0]
	pos.value.x = dragStart.value.ex + (touch.clientX - dragStart.value.mx)
	pos.value.y = dragStart.value.ey + (touch.clientY - dragStart.value.my)
	e.preventDefault()
}
function onTouchEnd() {
	if (longPressTimer.value) { clearTimeout(longPressTimer.value); longPressTimer.value = null }
	if (isDragging.value && header.value) header.value.style.opacity = '1'
	isDragging.value = false
}

onMounted(() => {
	document.addEventListener('mousemove', onMouseMove)
	document.addEventListener('mouseup',   onMouseUp)
	document.addEventListener('touchmove', onTouchMove, { passive: false })
	document.addEventListener('touchend',  onTouchEnd)
	document.addEventListener('touchcancel', onTouchEnd)
})
onUnmounted(() => {
	document.removeEventListener('mousemove', onMouseMove)
	document.removeEventListener('mouseup',   onMouseUp)
	document.removeEventListener('touchmove', onTouchMove)
	document.removeEventListener('touchend',  onTouchEnd)
	document.removeEventListener('touchcancel', onTouchEnd)
})

// ── Navball ───────────────────────────────────────────────────────────────────
const navball = computed(() => {
	const data           = props.plane
	const heading        = data.heading ?? data.track ?? 0
	const airspeedKnots  = data.speed || data.gs || 0
	const vertRateFps    = data.climb || data.baro_rate || 0
	const groundSpeedFps = airspeedKnots * 1.68781
	const pitchRad       = groundSpeedFps > 0 ? Math.atan(vertRateFps / groundSpeedFps) : 0
	const pitch          = Math.max(-25, Math.min(25, pitchRad * (180 / Math.PI)))

	const pitchLines: string[] = []
	for (let p = -30; p <= 30; p += 5) {
		if (p === 0) continue
		const isMajor      = p % 10 === 0
		const [start, end] = [85, 115]
		if (isMajor) {
			pitchLines.push(`
        <text x="${start - Math.abs(p) - 5}" y="${104 + pitch * 2.5 - p * 2.5}" fill="#fff" font-size="8" font-weight="bold" text-anchor="end">${Math.abs(p)}</text>
        <line x1="${start - Math.abs(p)}" y1="${100 + pitch * 2.5 - p * 2.5}" x2="${end + Math.abs(p)}" y2="${100 + pitch * 2.5 - p * 2.5}" stroke="#fff" stroke-width="2"/>
        <text x="${end + Math.abs(p) + 5}" y="${104 + pitch * 2.5 - p * 2.5}" fill="#fff" font-size="8" font-weight="bold">${Math.abs(p)}</text>
      `)
		} else {
			pitchLines.push(`<line x1="${start}" y1="${100 + pitch * 2.5 - p * 2.5}" x2="${end}" y2="${100 + pitch * 2.5 - p * 2.5}" stroke="#fff" stroke-width="2"/>`)
		}
	}

	const rollTicks: string[] = []
	for (const angle of [-90, -60, -45, -30, -20, -10, 0, 10, 20, 30, 45, 60, 90]) {
		const rad = angle * Math.PI / 180
		const a   = Math.abs(angle)
		if (a === 45) {
			rollTicks.push(`<circle cx="${100 + 78 * Math.sin(rad)}" cy="${100 - 78 * Math.cos(rad)}" r="2.5" fill="#fff"/>`)
		} else {
			const inner = (a === 0 || a % 30 === 0) ? 72 : 77
			const sw    = (a === 0 || a % 30 === 0) ? 2.5 : 1.5
			rollTicks.push(`<line x1="${100 + inner * Math.sin(rad)}" y1="${100 - inner * Math.cos(rad)}" x2="${100 + 85 * Math.sin(rad)}" y2="${100 - 85 * Math.cos(rad)}" stroke="#fff" stroke-width="${sw}"/>`)
		}
	}

	const compassLabels = [-60, -45, -30, -15, 0, 15, 30, 45, 60].map(offset => {
		const rad = offset * Math.PI / 180
		const x   = 100 + 90 * Math.sin(rad)
		const y   = 100 - 90 * Math.cos(rad)
		const h   = Math.round((offset + 360) % 360)
		const lbl = ({ 0: 'N', 90: 'E', 180: 'S', 270: 'W' } as any)[h] || ''
		return lbl ? `<text x="${x}" y="${y + 4}" text-anchor="middle" fill="#0f0" font-size="13" font-weight="bold">${lbl}</text>` : ''
	}).join('')

	return `
    <svg width="200" height="220" viewBox="0 0 200 220">
      <defs>
        <clipPath id="navballClip"><circle cx="100" cy="100" r="85"/></clipPath>
        <linearGradient id="skyGrad" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%"   style="stop-color:#1e90ff"/>
          <stop offset="100%" style="stop-color:#4169e1"/>
        </linearGradient>
        <linearGradient id="groundGrad" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%"   style="stop-color:#8b4513"/>
          <stop offset="100%" style="stop-color:#654321"/>
        </linearGradient>
      </defs>
      <rect x="77" y="5" width="46" height="18" fill="rgba(0,0,0,0.95)" stroke="#0f0" stroke-width="2" rx="2"/>
      <text x="100" y="18" text-anchor="middle" fill="#0f0" font-size="14" font-weight="bold">${heading.toFixed(0).padStart(3, '0')}°</text>
      <g transform="translate(0,25)" clip-path="url(#navballClip)">
        <rect x="15" y="${15 + pitch * 2.5 - 200}" width="170" height="285" fill="url(#skyGrad)"/>
        <rect x="15" y="${100 + pitch * 2.5}" width="170" height="285" fill="url(#groundGrad)"/>
        <line x1="15" y1="${100 + pitch * 2.5}" x2="185" y2="${100 + pitch * 2.5}" stroke="#fff" stroke-width="3"/>
        ${pitchLines.join('')}
      </g>
      <g transform="translate(0,25)">${rollTicks.join('')}</g>
      <circle cx="100" cy="125" r="85" fill="none" stroke="#0f0" stroke-width="2.5"/>
      <line x1="40"  y1="125" x2="80"  y2="125" stroke="#ff0" stroke-width="3.5"/>
      <line x1="120" y1="125" x2="160" y2="125" stroke="#ff0" stroke-width="3.5"/>
      <circle cx="100" cy="125" r="4" fill="none" stroke="#ff0" stroke-width="2.5"/>
      <g transform="rotate(${-heading} 100 125)">${compassLabels}</g>
      <polygon points="100,37 95,30 105,30" fill="#ff0"/>
    </svg>
  `
})
</script>

<template>
	<div class="aircraft-popup" :style="{ left: pos.x + 'px', top: pos.y + 'px' }">

		<!-- Header (drag handle) -->
		<div ref="header" class="ap-header" @mousedown="onMouseDown" @touchstart.passive="onTouchStart">
			<h3 class="ap-callsign">
				✈️
				<a v-if="callsign" :href="`https://www.flightaware.com/live/flight/${callsign}`" target="_blank" @click.stop>{{ callsign.toUpperCase() }}</a>
				<span v-else>N/A</span>
				<span style="color: white"> / {{ (plane.icao || plane.hex || '').toUpperCase() }}</span>
			</h3>
			<button class="ap-close" @click.stop="emit('close')">×</button>
		</div>

		<!-- Body -->
		<div class="ap-meta flex-r justify-between">
			<div class="flex-c">
				<span>{{ operator }}</span>
				<span>{{ plane.country || 'Unknown Country' }}</span>
			</div>
			<div class="flex-c align-x-end">
				<span>{{ description }}</span>
				<span style="text-transform: capitalize">{{ plane.class || 'Unknown' }} • {{ plane.type || 'Unknown' }}</span>
			</div>
		</div>
		<div class="ap-body">
			<div class="ap-gauges">
				<div class="ap-gauge-wrap">
					<div class="ap-gauge-label">Air Speed</div>
					<div class="ap-gauge" @click.stop="cycleSpeed">
						<span class="ap-gauge-val">{{ speedVal }}</span>
						<span class="ap-gauge-unit">{{ speed.label }}</span>
					</div>
				</div>
				<div class="ap-gauge-wrap">
					<div class="ap-gauge-label">Altitude</div>
					<div class="ap-gauge" @click.stop="cycleAltitude">
						<span class="ap-gauge-val">{{ altVal }}</span>
						<span class="ap-gauge-unit">{{ altUnit }}</span>
					</div>
				</div>
				<div class="ap-gauge-wrap">
					<div class="ap-gauge-label">Climb</div>
					<div class="ap-gauge" @click.stop="cycleVertical">
						<span class="ap-gauge-val">{{ climbVal }}</span>
						<span class="ap-gauge-unit">{{ vertical.label }}</span>
					</div>
				</div>
			</div>
			<div class="ap-navball" v-html="navball" />
		</div>

	</div>
</template>

<style scoped>
.aircraft-popup {
	position: fixed;
	z-index: 9999;
	pointer-events: auto;
	background: rgba(0,0,0,0.88);
	border: 1px solid rgba(200,200,220,0.3);
	border-radius: 8px;
	box-shadow: 0 4px 24px rgba(0,0,0,0.5);
	overflow: hidden;
	font-family: monospace;
	color: #ccc;
	min-width: 320px;
}

.ap-header {
	position: relative;
	padding: 12px 16px;
	border-bottom: 1px solid rgba(200,200,220,0.2);
	cursor: move;
	user-select: none;
	-webkit-user-select: none;
}

.ap-callsign {
	margin: 0 24px 0 0;
	color: #7eeee1;
	font-size: 16px;
}
.ap-callsign a { color: #6bb6ff; text-decoration: none; }

.ap-meta {
	font-size: 11px;
	color: #888;
	margin-top: 4px;
	display: flex;
	justify-content: space-between;
	gap: 8px;
	padding: 12px 16px;
	border-bottom: 1px solid rgba(200,200,220,0.2);
}
.ap-meta--detail { margin-top: 3px; }

.ap-icao    { text-align: right; }
.ap-operator { text-align: right; color: #aaa; }

.ap-close {
	position: absolute;
	top: 8px;
	right: 8px;
	background: rgba(255,255,255,0.2);
	border: none;
	color: white;
	width: 24px;
	height: 24px;
	border-radius: 4px;
	cursor: pointer;
	font-size: 16px;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background 0.2s;
}
.ap-close:hover { background: rgba(255,255,255,0.35); }

.ap-body {
	display: flex;
	gap: 16px;
	padding: 12px 16px;
}

.ap-gauges     { flex: 0 0 110px; }
.ap-gauge-wrap { margin-bottom: 12px; }

.ap-gauge-label {
	color: #888;
	font-size: 11px;
	font-weight: bold;
	margin-bottom: 3px;
}

.ap-gauge {
	padding: 6px;
	background: rgba(0,0,0,0.95);
	border: 2px solid #0f0;
	border-radius: 3px;
	cursor: pointer;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	gap: 4px;
	transition: border-color 0.15s;
}
.ap-gauge:hover  { border-color: #0ff; }
.ap-gauge-val    { font-size: 20px; font-weight: bold; color: #0f0; }
.ap-gauge-unit   { font-size: 11px; color: #0f0; margin-bottom: 2px; }
.ap-navball      { flex: 1; }
</style>
