import { BASE } from '@/services/api.ts'
import { createApp, ref } from 'vue'
import Map from 'ol/Map'
import { Feature } from 'ol'
import Point from 'ol/geom/Point'
import { fromLonLat } from 'ol/proj'
import { Style, Icon } from 'ol/style'
import { Vector as VectorLayer } from 'ol/layer'
import { Vector as VectorSource } from 'ol/source'
import { adjustedInterval } from '@ztimson/utils'
import ShipPopup from '@/components/Ship.vue'
import { bringToFront } from './zindex'

const API = BASE + '/api'

const SHIP_COLORS: Record<string, string> = {
	'Base Station':   '#ffffff',
	'Class A':        '#00ff00',
	'Class B':        '#8450ea',
	'SAR Aircraft':   '#ff0000',
	'AtoN':           '#ffffff',
	'Class B/CS':     '#8450ea',
	'Sart/Epirb/MOB': '#00aaff',
	'Unknown':        '#fad106',
}

function buildBoatIcon(boat: any): string {
	const color = SHIP_COLORS[boat.type] || SHIP_COLORS['Unknown']
	if (['Base Station', 'AtoN'].includes(boat.type)) {
		return `data:image/svg+xml,${encodeURIComponent(`
            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                <polygon points="16,2 30,16 16,30 2,16" fill="${color}" stroke="#000" stroke-width="1.5"/>
                <circle cx="16" cy="9" r="1.8" fill="#000"/>
                <line x1="16" y1="9" x2="16" y2="23" stroke="#000" stroke-width="1.8"/>
                <line x1="11" y1="12" x2="21" y2="12" stroke="#000" stroke-width="1.8"/>
                <path d="M9,18 Q16,26 23,18" fill="none" stroke="#000" stroke-width="1.5"/>
            </svg>
        `)}`
	}
	return `data:image/svg+xml,${encodeURIComponent(`
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="32" viewBox="0 0 24 32">
            <polygon points="12,0 24,30 12,24 0,30" fill="${color}" stroke="#000" stroke-width="1.5"/>
            <circle cx="12" cy="12" r="1.5" fill="#000"/>
            <line x1="12" y1="12" x2="12" y2="22" stroke="#000" stroke-width="1.5"/>
            <line x1="8" y1="14" x2="16" y2="14" stroke="#000" stroke-width="1.5"/>
            <path d="M7,17 Q12,24 17,17" fill="none" stroke="#000" stroke-width="1.3"/>
        </svg>
    `)}`
}

export class AISLayer {
	private map:          Map
	private layer!:       VectorLayer<VectorSource>
	private popups:       any                       = {}
	private data:         any[]                     = []
	private clickHandler: ((e: any) => void) | null = null
	private refreshTimer: any                       = null
	visible = false

	constructor(map: Map) { this.map = map }

	async show() {
		if (this.visible) return
		this.visible = true
		this.layer   = new VectorLayer({ source: new VectorSource(), zIndex: 100 })
		this.map.addLayer(this.layer)
		await this._fetch()
		this._draw()
		this._attachClick()
		this.refreshTimer = adjustedInterval(async () => {
			try {
				await this._fetch()
				this._draw()
				this._refreshPopups()
			} catch (err) {
				console.error(err);
			}
		}, 5_000)
	}

	hide() {
		if (!this.visible) return
		this.visible = false
		if (this.refreshTimer) { clearInterval(this.refreshTimer); this.refreshTimer = null }
		if (this.clickHandler) { this.map.un('singleclick', this.clickHandler); this.clickHandler = null }
		for (const mmsi of Object.keys(this.popups)) this._closePopup(mmsi)
		this.map.removeLayer(this.layer)
	}

	private async _fetch() {
		this.data = await fetch(`${API}/ais`).then(r => r.json()) || []
	}

	private _draw() {
		const source = this.layer.getSource()!
		source.clear()
		for (const boat of this.data) {
			if (boat.lat == null || boat.lon == null) continue
			const coord = fromLonLat([boat.lon, boat.lat])
			const f     = new Feature({ geometry: new Point(coord) })
			f.set('mmsi',     boat.mmsi)
			f.set('boatData', boat)
			f.setStyle(new Style({
				image: new Icon({
					src:      buildBoatIcon(boat),
					scale:    0.8,
					rotation: (boat.heading ?? boat.course ?? 0) * (Math.PI / 180),
					anchor:   [0.5, 0.5],
				}),
			}))
			source.addFeature(f)
		}
	}

	private _calcPopupPos(boat: any): { x: number; y: number } {
		const pixel: any = this.map.getPixelFromCoordinate(fromLonLat([boat.lon, boat.lat]))
		if (!pixel) return { x: 10, y: 60 }
		const rect = (this.map.getTargetElement() as HTMLElement).getBoundingClientRect()
		return { x: rect.left + pixel[0] + 16, y: rect.top + pixel[1] - 16 }
	}

	private _openPopup(boat: any) {
		const mmsi = String(boat.mmsi)
		if (this.popups[mmsi]) return

		const boatRef = ref(boat)
		const posRef  = ref(this._calcPopupPos(boat))

		const container = document.createElement('div')
		document.body.appendChild(container)

		const mobile = window.innerWidth <= 768;

		const app = createApp(ShipPopup, {
			boat:           boatRef.value,
			position:       mobile ? {x: window.innerWidth / 2 - 180, y: window.innerHeight - 540 - 16} : {x: window.innerWidth - 360 - 16, y: 16},
			onClose:        () => this._closePopup(mmsi),
			onBringToFront: () => bringToFront(container),
		})

		app.mount(container)
		this.popups[mmsi] = {
			boatRef,
			posRef,
			unmount: () => { app.unmount(); container.remove() },
		}
	}

	private _closePopup(mmsi: string) {
		const popup = this.popups[mmsi]
		if (popup) { popup.unmount(); delete this.popups[mmsi] }
	}

	private _refreshPopups() {
		for (const mmsi of Object.keys(this.popups)) {
			const boat = this.data.find(b => String(b.mmsi) === mmsi)
			if (!boat) { this._closePopup(mmsi); continue }
			this.popups[mmsi].boatRef.value = boat
		}
	}

	private _attachClick() {
		this.clickHandler = (evt) => {
			const f = this.map.forEachFeatureAtPixel(evt.pixel, f => f.get('boatData') ? f : null)
			if (!f) return
			const boat = f.get('boatData')
			const mmsi = String(boat.mmsi)
			if (this.popups[mmsi]) { this._closePopup(mmsi); return }
			this._openPopup(boat)
		}
		this.map.on('singleclick', this.clickHandler)
	}
}
