import { Prop, toNative } from 'vue-facing-decorator';
import { globalState } from '../../app/global-state';
import TsxComponent, { Component } from '../../app/vuetsx';
import { isNullOrEmpty } from '../../common/utils/is-null-or-empty';
import { PortalUtils } from '../../common/utils/utils';
import GoogleMapsApiLoader from './ts/google-maps-api';

interface GoogleMapArgs {
	latitude?: string;
	longitude?: string;
	name?: string;
	address?: string;
	is16by9?: boolean;
	defaultZoom?: number;
	geoJSON?: any;
	initComplete?: (map: any, GMaps: any) => void;
}

export interface GoogleMapRefreshArgs {
	autoCenter?: boolean;
}

@Component
class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMapArgs {
	@Prop() latitude!: string;
	@Prop() longitude!: string;
	@Prop() name!: string;
	@Prop() address!: string;
	@Prop() is16by9!: boolean;
	@Prop() defaultZoom?: number;
	@Prop() geoJSON?: any;
	@Prop() initComplete?: (map: any, GMaps: any) => void;
	map: any;
	infoWindow: any;
	marker: any;
	lastState: any;

	getNumeric(val: string): number {
		return Number((val || '').toString().split(',').join(''));
	}

	getLocPoint() {
		if (globalState.google?.maps?.LatLng) {
			return new globalState.google.maps.LatLng(this.latitude as any, this.longitude as any);
		}

		return {
			lat: this.getNumeric(this.latitude),
			lng: this.getNumeric(this.longitude),
		};
	}

	mounted() {
		// eslint-disable-next-line ts/no-this-alias
		const mySelf = this;
		globalState.mapInst = mySelf;
		if (!globalState.windowExists) {
			return;
		}

		GoogleMapsApiLoader.load().then((result) => {
			if (result) {
				const gmapArgs: any = {
					center: mySelf.getLocPoint(),
				};

				if (this.defaultZoom > 0) {
					gmapArgs.zoom = this.defaultZoom;
				} else {
					gmapArgs.zoom = 16;
				}

				mySelf.map = new globalState.google.maps.Map(mySelf.$refs.mapWrapper as any, gmapArgs);
				// eslint-disable-next-line no-useless-call
				mySelf.refreshMapItems.call(mySelf);
				globalState.mapInstance = mySelf.map;

				if (this.initComplete != null) {
					this.initComplete(mySelf.map, globalState.google.maps);
				}
			}
		});
	}

	updated() {
		this.refreshMapItems();
	}

	getCurrentState() {
		return {
			lat: this.latitude,
			lon: this.longitude,
			geoJSON: this.geoJSON,
		};
	}

	refreshMapItems(args?: GoogleMapRefreshArgs) {
		if (!globalState.windowExists) {
			return;
		}

		const map = this.map;
		const locPoint = this.getLocPoint();
		const newState = this.getCurrentState();

		if (this.lastState != null && JSON.stringify(newState) == JSON.stringify(this.lastState)) {
			return;
		}

		if (this.lastState != null && args?.autoCenter != false) {
			map.setCenter(locPoint);
		}

		if (this.infoWindow == null && !isNullOrEmpty(this.name)) {
			this.infoWindow = new globalState.google.maps.InfoWindow({
				content: '',
			});
		}

		if (this.marker != null) {
			this.marker.setMap(null);
			this.marker = null;
		}

		if (this.marker == null) {
			this.marker = new globalState.google.maps.Marker({
				position: locPoint,
				title: PortalUtils.htmlEscape(this.name),
				visible: true,
			});

			this.marker.addListener('click', () => {
				this.infoWindow.open(map, this.marker);
			});
		}

		this.marker.position = locPoint;
		this.marker.title = PortalUtils.htmlEscape(this.name);
		this.marker.setMap(map);

		if (this.infoWindow != null) {
			this.infoWindow.setContent(`<b>${PortalUtils.htmlEscape(this.name)}</b><br> ${PortalUtils.htmlEscape(this.address)}`);
			this.infoWindow.open(map, this.marker);
		}

		if (!isNullOrEmpty(this.geoJSON)) {
			map.data.addGeoJson(this.geoJSON);
		}

		this.lastState = this.getCurrentState();
	}

	render(h) {
		if (this.is16by9 == false) {
			return <div class="google-map-wrapper" ref="mapWrapper"></div>;
		}

		return (
			<div style="width: 100%;position: relative;padding-top: 56.25%;">
				<div class="rounded" style="position: absolute; top: 0;left: 0; bottom: 0;right: 0;" ref="mapWrapper"></div>
			</div>
		);
	}
}

const GoogleMap = toNative(GoogleMapComponent);
export default GoogleMap;
