<script setup lang="ts">
import {BASE} from '@/services/api.ts';
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'

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

const SPEED_UNITS = {
	knots: { label: 'KTS', convert: (v: number) => v.toFixed(1) },
	kph:   { label: 'KPH', convert: (v: number) => (v * 1.852).toFixed(1) },
	mph:   { label: 'MPH', convert: (v: number) => (v * 1.15078).toFixed(1) },
}
const UNIT_KEY = 'ais_units'
function loadUnits() {
	const s = localStorage.getItem(UNIT_KEY)
	return s ? JSON.parse(s) : { speed: 'knots' }
}
const prefs = ref(loadUnits())
function cycleSpeed() {
	const keys = Object.keys(SPEED_UNITS)
	const p = loadUnits()
	p.speed = keys[(keys.indexOf(p.speed) + 1) % keys.length]
	prefs.value = { ...p }
	localStorage.setItem(UNIT_KEY, JSON.stringify(p))
}
const speed = computed(() => SPEED_UNITS[prefs.value.speed as keyof typeof SPEED_UNITS])

const name     = computed(() => props.boat.shipname?.trim() || props.boat.callsign?.trim() || '-')
const heading  = computed(() => props.boat.heading ?? props.boat.course ?? 0)
const speedVal = computed(() => speed.value.convert(props.boat.speed ?? 0))
const photoError = ref(false)

// ── 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('sp-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('sp-close')) return
	const touch: any = 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: any = 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)
})

const compass = computed(() => {
	const hdg     = heading.value
	const course  = props.boat.cog ?? hdg

	const tapeTicks: string[] = []
	for (let offset = -60; offset <= 60; offset += 5) {
		const deg   = ((hdg + offset) % 360 + 360) % 360
		const x     = 100 + (offset / 60) * 90
		const major = offset % 30 === 0
		const mid   = offset % 15 === 0
		if (major) {
			const lbl = ({ 0: 'N', 45: 'NE', 90: 'E', 135: 'SE', 180: 'S', 225: 'SW', 270: 'W', 315: 'NW' } as any)[deg]
				?? String(deg).padStart(3, '0')
			tapeTicks.push(`
                <line x1="${x}" y1="22" x2="${x}" y2="38" stroke="#0ff" stroke-width="2"/>
                <text x="${x}" y="50" text-anchor="middle" fill="#0ff" font-size="11" font-weight="bold">${lbl}</text>
            `)
		} else if (mid) {
			tapeTicks.push(`<line x1="${x}" y1="26" x2="${x}" y2="38" stroke="#0ff" stroke-width="1.5"/>`)
		} else {
			tapeTicks.push(`<line x1="${x}" y1="30" x2="${x}" y2="38" stroke="#0ff" stroke-width="1"/>`)
		}
	}

	const CX = 100, CY = 140
	const R  = 68

	const rudder = Math.max(-30, Math.min(30, ((course - hdg + 540) % 360) - 180))
	const rudX   = CX + (rudder / 30) * 40

	const courseRel = ((course - hdg + 540) % 360) - 180
	const courseRad = courseRel * Math.PI / 180
	const cNeedleX  = CX + 52 * Math.sin(courseRad)
	const cNeedleY  = CY - 52 * Math.cos(courseRad)

	const bearRel  = ((course - hdg + 540) % 360) - 180
	const bearRad  = bearRel * Math.PI / 180
	const bNeedleX = CX + 52 * Math.sin(bearRad)
	const bNeedleY = CY - 52 * Math.cos(bearRad)

	const ringTicks = Array.from({ length: 36 }, (_, i) => {
		const a   = i * 10
		const rad = (a - 90) * Math.PI / 180
		const r1  = a % 30 === 0 ? R - 11 : R - 5
		const sw  = a % 30 === 0 ? 2 : 1
		const x1  = CX + r1  * Math.cos(rad)
		const y1  = CY + r1  * Math.sin(rad)
		const x2  = CX + R   * Math.cos(rad)
		const y2  = CY + R   * Math.sin(rad)
		return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="#0ff" stroke-width="${sw}" opacity="0.5"/>`
	}).join('')

	const cardinals = (['N','E','S','W'] as const).map((lbl, i) => {
		const a   = i * 90
		const rad = (a - 90) * Math.PI / 180
		const x   = CX + (R - 18) * Math.cos(rad)
		const y   = CY + (R - 18) * Math.sin(rad) + 4
		return `<text x="${x}" y="${y}" text-anchor="middle" fill="#0ff" font-size="10" font-weight="bold" opacity="0.8">${lbl}</text>`
	}).join('')

	return `
        <svg width="200" height="210" viewBox="0 0 200 210">
            <rect x="10" y="18" width="180" height="40" fill="rgba(0,20,40,0.95)" rx="3"/>
            <line x1="10" y1="18" x2="190" y2="18" stroke="#0ff" stroke-width="1"/>
            <line x1="10" y1="58" x2="190" y2="58" stroke="#0ff" stroke-width="1"/>
            ${tapeTicks.join('')}
            <polygon points="100,20 96,12 104,12" fill="#ff0"/>

            <circle cx="${CX}" cy="${CY}" r="${R}" fill="rgba(0,20,40,0.6)" stroke="#0ff" stroke-width="1.5"/>
            <circle cx="${CX}" cy="${CY}" r="${R - 20}" fill="none" stroke="rgba(0,255,255,0.15)" stroke-width="1"/>

            <g transform="rotate(${-hdg}, ${CX}, ${CY})">
                ${ringTicks}
                ${cardinals}
            </g>

            <line x1="${CX}" y1="${CY}" x2="${bNeedleX}" y2="${bNeedleY}" stroke="#ff0" stroke-width="1.5" stroke-dasharray="4,3"/>
            <circle cx="${bNeedleX}" cy="${bNeedleY}" r="2.5" fill="#ff0"/>

            <line x1="${CX}" y1="${CY}" x2="${cNeedleX}" y2="${cNeedleY}" stroke="#0f0" stroke-width="2.5"/>
            <circle cx="${cNeedleX}" cy="${cNeedleY}" r="3" fill="#0f0"/>

            <polygon points="${CX},${CY - 9} ${CX - 4},${CY + 5} ${CX},${CY + 2} ${CX + 4},${CY + 5}" fill="#fff" stroke="#0ff" stroke-width="1"/>

            <rect x="80" y="${CY + 23}" width="40" height="6" fill="rgba(0,50,70,0.9)" rx="3"/>
            <rect x="${rudX - 4}" y="${CY + 22}" width="8" height="8" fill="#ff0" rx="1"/>

            <line x1="10" y1="${CY + 55}" x2="20" y2="${CY + 55}" stroke="#0f0" stroke-width="2"/>
            <text x="25" y="${CY + 57}" fill="#888" font-size="9">COG</text>

            <line x1="10" y1="${CY + 65}" x2="20" y2="${CY + 65}" stroke="#ff0" stroke-width="1.5" stroke-dasharray="4,3"/>
            <text x="25" y="${CY + 67}" fill="#888" font-size="9">BRG</text>
        </svg>
    `
})
</script>

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

		<div ref="header" class="sp-header" @mousedown="onMouseDown" @touchstart.passive="onTouchStart">
			<h3 class="sp-name">
				🚢
				<span>{{ name.toUpperCase() }}</span>
				<span class="sp-mmsi"> / {{ boat.mmsi }}</span>
			</h3>
			<button class="sp-close" @click.stop="emit('close')">×</button>
		</div>

		<div class="sp-meta">
			<div class="flex-c">
				<span>{{ boat.operator || boat.owner || 'Unknown Owner' }}</span>
				<span>{{ boat.country || 'Unknown Country' }}</span>
			</div>
			<div class="flex-c align-x-end">
				<span style="text-transform:capitalize">{{ boat.type || 'Unknown' }}</span>
				<span>{{ boat.ship_type || 'Unknown Class' }}</span>
			</div>
		</div>

		<!-- Photo -->
		<div v-if="!photoError" class="sp-photo-wrap">
			<img class="sp-photo" :src="BASE + '/api/ais-iamge/' + boat.mmsi" :alt="name" @error="photoError = true" />
		</div>

		<div class="sp-body">
			<div class="sp-gauges">
				<div class="sp-gauge-wrap">
					<div class="sp-gauge-label">Speed</div>
					<div class="sp-gauge" @click.stop="cycleSpeed">
						<span class="sp-gauge-val">{{ speedVal }}</span>
						<span class="sp-gauge-unit">{{ speed.label }}</span>
					</div>
				</div>
				<div class="sp-gauge-wrap">
					<div class="sp-gauge-label">Course</div>
					<div class="sp-gauge">
						<span class="sp-gauge-val">{{ boat.course != null ? boat.course.toFixed(0) : '—' }}</span>
						<span v-if="boat.course != null" class="sp-gauge-unit">°</span>
					</div>
				</div>
				<div class="sp-gauge-wrap">
					<div class="sp-gauge-label">Heading</div>
					<div class="sp-gauge">
						<span class="sp-gauge-val">{{ boat.heading != null ? boat.heading.toFixed(0) : '—' }}</span>
						<span v-if="boat.heading != null" class="sp-gauge-unit">°</span>
					</div>
				</div>
			</div>

			<div class="sp-compass" v-html="compass"/>
		</div>
	</div>
</template>

<style scoped>
.ship-popup {
	position: fixed;
	z-index: 100;
	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;
	max-width: 360px;
}

.sp-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;
}

.sp-name {
	margin: 0 24px 0 0;
	color: #7eeee1;
	font-size: 16px;
}
.sp-mmsi { color: white; }

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

.sp-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;
}
.sp-close:hover { background: rgba(255,255,255,0.35); }

/* ── Photo ── */
.sp-photo-wrap {
	width: 100%;
	height: 140px;
	background: #111;
	border-bottom: 1px solid rgba(200,200,220,0.15);
	overflow: hidden;
}
.sp-photo {
	width: 100%;
	height: 140px;
	object-fit: cover;
	display: block;
}

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

.sp-gauges     { flex: 0 0 110px; display: flex; flex-direction: column; gap: 0; }
.sp-gauge-wrap { margin-bottom: 12px; }

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

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