import { getLeftBlock, getRightBlock, directionState } from '../util/globalVariables';

export class McfFenceGate {
	constructor() {
		this.onPlace = this.onPlace.bind(this);
		this.onPlayerBreak = this.onPlayerBreak.bind(this);
		this.onPlayerInteract = this.onPlayerInteract.bind(this);
		this.beforeOnPlayerPlace = this.beforeOnPlayerPlace.bind(this);
	}
	onPlayerInteract(e, p) {
		const { block, dimension } = e;
		const per = block.permutation;
		const direction = per.getState(directionState)
		const open = per.getState("mr:open");
		const right = per.getState("mr:right");
		const side = per.getState("mr:side");
		dimension.playSound(open ? p.params.close_sound : p.params.open_sound, block.center());
		this.toggleGateAndConnected(block, side, right, direction, !open)
	}
	beforeOnPlayerPlace(e) {
		const direction = e.permutationToPlace.getState(directionState);
		const leftBlock = getRightBlock(e.block, direction);
		e.permutationToPlace = e.permutationToPlace.withState("mr:right", leftBlock.hasTag("mcf:fence_gate_left"));
	}
	onPlace(e) {
		const direction = e.block.permutation.getState(directionState);
		this.updateGateState(e.block, direction);
		this.updateNearestGate(e.block, direction);
	}
	onPlayerBreak(e) {
		const direction = e.brokenBlockPermutation.getState(directionState);
		this.updateNearestGate(e.block, direction);
	}
	toggleGateAndConnected(block, isSide, isRightBlock, direction, newOpenState) {
		const blocksToToggle = new Set([block]);
		this.findConectedVerticalBlocks(block, isSide, isRightBlock).forEach(b => blocksToToggle.add(b));
		if (isSide) {
			const neighbor = isRightBlock ? getRightBlock(block, direction) : getLeftBlock(block, direction);
			if (neighbor?.hasTag("mcf:fence_gate")) {
				blocksToToggle.add(neighbor);
				this.findConectedVerticalBlocks(
					neighbor,
					neighbor.permutation.getState("mr:side"),
					neighbor.permutation.getState("mr:right")
				).forEach(b => blocksToToggle.add(b));
			}
		}
		blocksToToggle.forEach(targetBlock => {
			targetBlock.setPermutation(targetBlock.permutation.withState("mr:open", newOpenState));
		});
	}
	findConectedVerticalBlocks(baseBlock, isSide, isRightBlock, maxHeight = 10) {
		const connectedBlocks = [];
		for (const dir of [1, -1]) {
			let currentBlock = baseBlock;
			for (let i = 0; i < maxHeight; i++) {
				const nextBlock = currentBlock.offset({ x: 0, y: dir, z: 0 });
				if (!nextBlock?.hasTag("mcf:fence_gate")) break;
				const sameConfig = nextBlock.permutation.getState("mr:right") === isRightBlock && nextBlock.permutation.getState("mr:side") === isSide;
				if (sameConfig) {
					connectedBlocks.push(nextBlock);
					currentBlock = nextBlock;
				} else break;
			}
		}
		return connectedBlocks;
	}
	updateGateState(block, direction) {
		const rightBlock = getLeftBlock(block, direction);
		const leftBlock = getRightBlock(block, direction);
		const rightState = block.permutation.getState("mr:right");
		block.setPermutation(block.permutation
			.withState("mr:side", (!rightState && rightBlock.hasTag("mcf:fence_gate_right")) || (rightState && leftBlock.hasTag("mcf:fence_gate_left")))
		);
	}
	updateNearestGate(block, direction) {
		const rightBlock = getLeftBlock(block, direction);
		const leftBlock = getRightBlock(block, direction);
		if (rightBlock.hasTag("mcf:fence_gate")) this.updateGateState(rightBlock, rightBlock.permutation.getState(directionState));
		if (leftBlock.hasTag("mcf:fence_gate")) this.updateGateState(leftBlock, leftBlock.permutation.getState(directionState));
	}
}