import type { ValidationState } from '../../common/static-wrappers/interfaces/validation-interface';
import type { GeoJSON } from './../../data/geo';
import { Prop, toNative } from 'vue-facing-decorator';
import PowerduckState from '../../app/powerduck-state';
import TsxComponent, { Component } from '../../app/vuetsx';
import BoundingBox from '../../data/bounding-box';
import FlexContainer from '../form/flex-container';
import FlexFormItem from '../form/form-item-flex';
import FormItemWrapper from '../form/form-item-wrapper';
import OpenStreetMap from '../open-street-map/open-street-map';
import GeoJsonEditor from './geo-json';
import NumericInput, { NumericInputMode } from './numeric-input';

interface GpsInputArgs {
	gpsModel: { latitude: number; longitude: number; geoJSON?: GeoJSON };
	hasGeoJsonInput?: boolean;
	mandatory?: boolean;
	showClearValueButton?: boolean;
	validationStateLatitude: ValidationState;
	validationStateLongitude: ValidationState;
	disabled?: boolean;
}

@Component
class GpsInputComponent extends TsxComponent<GpsInputArgs> implements GpsInputArgs {
	@Prop() gpsModel: { latitude: number; longitude: number; geoJSON?: GeoJSON };
	@Prop() hasGeoJsonInput?: boolean;
	@Prop() mandatory?: boolean = true;
	@Prop() showClearValueButton!: boolean;
	@Prop() validationStateLatitude: ValidationState;
	@Prop() validationStateLongitude: ValidationState;
	@Prop() disabled?: boolean;

	handleMapInitComplete(leaflet) {
		leaflet?.on('contextmenu', (e) => {
			if (this.disabled) {
				return;
			}

			const coord = e.latlng;
			// QA_AT-11: Leaflet emits ~15-decimal floats. Round BOTH axes to 6
			// decimals at the point of the model write so the bound NumericInputs
			// display and store exactly 6 decimals IMMEDIATELY — this map
			// right-click path bypasses both the NumericInput typing-time clamp
			// (DOM onInput only) and the `changed`-callback blur-time round.
			this.gpsModel.latitude = BoundingBox.roundCoord(coord.lat);
			this.gpsModel.longitude = BoundingBox.roundCoord(coord.lng);
			this.$nextTick(() => {
				this.$forceUpdate();
			});
		});
	}

	render(h) {
		return (
			<div>
				<FormItemWrapper label={PowerduckState.getResourceValue('gpsLabel')} mandatory={this.mandatory}>
					<FlexContainer fullWidthOnMobile={true}>
						<FlexFormItem flexFill={true}>
							<NumericInput
								wrap={false}
								mandatory={this.mandatory}
								subtitle={PowerduckState.getResourceValue('gpsSubtitle')}
								placeholder={PowerduckState.getResourceValue('gpsLatitudeCaption')}
								label={null}
								value={this.gpsModel.latitude}
								step={0.000001}
								maxDecimals={6}
								mode={NumericInputMode.Clasic}
								showClearValueButton={this.showClearValueButton}
								validationState={this.validationStateLatitude}
								disabled={this.disabled}
								changed={(e) => {
									// QA_AT-24: NumericInput string-truncates while typing
									// (via maxDecimals={6}). QA_AT-11: route the blur-time round
									// through the shared `BoundingBox.roundCoord` (same 6-dec
									// rule as the map-click path above and the server's
									// GpsHelper.roundCoord) — defence-in-depth for non-input
									// paths (programmatic centroid prefills, paste).
									this.gpsModel.latitude = BoundingBox.roundCoord(e);
								}}
							/>
						</FlexFormItem>
						<FlexFormItem flexFill={true}>
							<NumericInput
								wrap={false}
								placeholder={PowerduckState.getResourceValue('gpsLongitudeCaption')}
								label={null}
								value={this.gpsModel.longitude}
								step={0.000001}
								maxDecimals={6}
								mode={NumericInputMode.Clasic}
								showClearValueButton={this.showClearValueButton}
								validationState={this.validationStateLongitude}
								disabled={this.disabled}
								changed={(e) => {
									// QA_AT-24 / QA_AT-11: see latitude comment — same shared
									// `BoundingBox.roundCoord` 6-decimal net.
									this.gpsModel.longitude = BoundingBox.roundCoord(e);
								}}
							/>
						</FlexFormItem>
					</FlexContainer>
				</FormItemWrapper>

				{this.hasGeoJsonInput && (
					<GeoJsonEditor
						value={this.gpsModel.geoJSON}
						changed={(e) => {
							this.gpsModel.geoJSON = e;
						}}
					/>
				)}

				<FormItemWrapper label={null} mandatory={false}>
					<div class="rounded">
						<OpenStreetMap
							ref="openStreetMap"
							latitude={this.gpsModel.latitude != null ? this.gpsModel.latitude.toString() : null}
							longitude={this.gpsModel.longitude != null ? this.gpsModel.longitude.toString() : null}
							geoJSON={this.gpsModel.geoJSON}
							defaultZoom={this.gpsModel.geoJSON != null ? 15 : 12}
							initComplete={(map) => {
								this.handleMapInitComplete(map);
							}}
						/>
					</div>
				</FormItemWrapper>
			</div>
		);
	}
}

const GpsInput = toNative(GpsInputComponent);
export default GpsInput;
