import { DOUBLE_TAP_VARIANCE, DOUBLE_TAP_THRESHOLD } from '../constants.js';
import { InputSource } from '../input.js';
import { VirtualJoystick } from './virtual-joystick.js';

const startsWith = (str, prefix)=>str.indexOf(prefix) === 0;
const endsWith = (str, suffix)=>str.indexOf(suffix, str.length - suffix.length) !== -1;
class DualGestureSource extends InputSource {
		constructor(layout){
				super({
						leftInput: [
								0,
								0
						],
						rightInput: [
								0,
								0
						],
						doubleTap: [
								0
						]
				}), this._layout = 'joystick-touch', this._pointerData = new Map(), this._lastPointer = {
						x: 0,
						y: 0,
						time: 0
				};
				if (layout) {
						this.layout = layout;
				}
				this._leftJoystick = new VirtualJoystick();
				this._rightJoystick = new VirtualJoystick();
				this._onPointerDown = this._onPointerDown.bind(this);
				this._onPointerMove = this._onPointerMove.bind(this);
				this._onPointerUp = this._onPointerUp.bind(this);
		}
		set layout(value) {
				if (this._layout === value) {
						return;
				}
				this._layout = value;
				this.read();
				this._pointerData.clear();
		}
		get layout() {
				return this._layout;
		}
		get leftJoystick() {
				return this._leftJoystick;
		}
		get rightJoystick() {
				return this._rightJoystick;
		}
		_onPointerDown(event) {
				const { pointerType, pointerId, clientX, clientY } = event;
				if (pointerType !== 'touch') {
						return;
				}
				this._element?.setPointerCapture(pointerId);
				const left = clientX < window.innerWidth * 0.5;
				this._pointerData.set(pointerId, {
						x: clientX,
						y: clientY,
						left
				});
				const now = Date.now();
				const sqrDist = (this._lastPointer.x - clientX) ** 2 + (this._lastPointer.y - clientY) ** 2;
				if (sqrDist < DOUBLE_TAP_VARIANCE && now - this._lastPointer.time < DOUBLE_TAP_THRESHOLD) {
						this.deltas.doubleTap.append([
								1
						]);
				}
				this._lastPointer.x = clientX;
				this._lastPointer.y = clientY;
				this._lastPointer.time = now;
				if (left && startsWith(this._layout, 'joystick')) {
						this.fire('joystick:position:left', this._leftJoystick.down(clientX, clientY));
				}
				if (!left && endsWith(this._layout, 'joystick')) {
						this.fire('joystick:position:right', this._rightJoystick.down(clientX, clientY));
				}
		}
		_onPointerMove(event) {
				const { pointerType, pointerId, target, clientX, clientY, movementX, movementY } = event;
				if (pointerType !== 'touch') {
						return;
				}
				if (target !== this._element) {
						return;
				}
				const data = this._pointerData.get(pointerId);
				if (!data) {
						return;
				}
				const { left } = data;
				data.x = clientX;
				data.y = clientY;
				if (left) {
						if (startsWith(this._layout, 'joystick')) {
								this.fire('joystick:position:left', this._leftJoystick.move(clientX, clientY));
						} else {
								this.deltas.leftInput.append([
										movementX,
										movementY
								]);
						}
				} else {
						if (endsWith(this._layout, 'joystick')) {
								this.fire('joystick:position:right', this._rightJoystick.move(clientX, clientY));
						} else {
								this.deltas.rightInput.append([
										movementX,
										movementY
								]);
						}
				}
		}
		_onPointerUp(event) {
				const { pointerType, pointerId } = event;
				if (pointerType !== 'touch') {
						return;
				}
				this._element?.releasePointerCapture(pointerId);
				const data = this._pointerData.get(pointerId);
				if (!data) {
						return;
				}
				const { left } = data;
				this._pointerData.delete(pointerId);
				if (left && startsWith(this._layout, 'joystick')) {
						this.fire('joystick:position:left', this._leftJoystick.up());
				}
				if (!left && endsWith(this._layout, 'joystick')) {
						this.fire('joystick:position:right', this._rightJoystick.up());
				}
		}
		attach(element) {
				super.attach(element);
				this._element = element;
				this._element.addEventListener('pointerdown', this._onPointerDown);
				this._element.addEventListener('pointermove', this._onPointerMove);
				this._element.addEventListener('pointerup', this._onPointerUp);
				this._element.addEventListener('pointercancel', this._onPointerUp);
		}
		detach() {
				if (!this._element) {
						return;
				}
				this._element.removeEventListener('pointerdown', this._onPointerDown);
				this._element.removeEventListener('pointermove', this._onPointerMove);
				this._element.removeEventListener('pointerup', this._onPointerUp);
				this._element.removeEventListener('pointercancel', this._onPointerUp);
				this._pointerData.clear();
				super.detach();
		}
		read() {
				this.deltas.leftInput.append([
						this._leftJoystick.value.x,
						this._leftJoystick.value.y
				]);
				this.deltas.rightInput.append([
						this._rightJoystick.value.x,
						this._rightJoystick.value.y
				]);
				return super.read();
		}
		destroy() {
				this._leftJoystick.up();
				this._rightJoystick.up();
				super.destroy();
		}
}

export { DualGestureSource };
