import { isAccelKey, StateNode, TLPointerEventInfo, TLShapeId } from '@tldraw/editor'

export class Pointing extends StateNode {
	static override id = 'pointing'

	_isHoldingAccelKey = false

	override onEnter() {
		this._isHoldingAccelKey = isAccelKey(this.editor.inputs)

		const zoomLevel = this.editor.getZoomLevel()
		const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()
		const currentPagePoint = this.editor.inputs.getCurrentPagePoint()

		const erasing = new Set<TLShapeId>()

		const initialSize = erasing.size

		for (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {
			const shape = currentPageShapesSorted[i]
			if (this.editor.isShapeOrAncestorLocked(shape) || this.editor.isShapeOfType(shape, 'group')) {
				continue
			}

			if (
				this.editor.isPointInShape(shape, currentPagePoint, {
					hitInside: false,
					margin: this.editor.options.hitTestMargin / zoomLevel,
				})
			) {
				const hitShape = this.editor.getOutermostSelectableShape(shape)
				// If we've hit a frame after hitting any other shape, stop here
				if (this.editor.isShapeOfType(hitShape, 'frame') && erasing.size > initialSize) {
					break
				}

				erasing.add(hitShape.id)

				// If the user is holding the meta / ctrl key, stop after the first shape
				if (this._isHoldingAccelKey) {
					break
				}
			}
		}

		this.editor.setErasingShapes([...erasing])
	}

	override onKeyUp() {
		this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
	}

	override onKeyDown() {
		this._isHoldingAccelKey = isAccelKey(this.editor.inputs)
	}

	override onLongPress(info: TLPointerEventInfo) {
		this.startErasing(info)
	}

	override onExit(_info: any, to: string) {
		if (to !== 'erasing') {
			this.editor.setErasingShapes([])
		}
	}

	override onPointerMove(info: TLPointerEventInfo) {
		if (this._isHoldingAccelKey) return

		if (this.editor.inputs.getIsDragging()) {
			this.startErasing(info)
		}
	}

	override onPointerUp() {
		this.complete()
	}

	override onCancel() {
		this.cancel()
	}

	override onComplete() {
		this.complete()
	}

	override onInterrupt() {
		this.cancel()
	}

	private startErasing(info: TLPointerEventInfo) {
		this.parent.transition('erasing', info)
	}

	complete() {
		const erasingShapeIds = this.editor.getErasingShapeIds()

		if (erasingShapeIds.length) {
			this.editor.markHistoryStoppingPoint('erase end')
			this.editor.deleteShapes(erasingShapeIds)
		}

		this.parent.transition('idle')
	}

	cancel() {
		this.parent.transition('idle')
	}
}
