import {world, system, ItemStack, ItemTypes, MinecraftBlockTypes} from '@minecraft/server';
    
export class GravityGun_Main{
	
	static run(){	
		//////////////////////////////////
		//CARRY BLOCK / PLACE BLOCK
		//////////////////////////////////
		system.runInterval(()=>{
			let allPlayers = world.getPlayers();
			for(let player of allPlayers){
				let viewDX = player.getViewDirection().x;
				let viewDY = player.getViewDirection().y;
				let viewDZ = player.getViewDirection().z;
				let carriedBlock = this.getGravityGunEntity({tags:[`${player.name},gg`,`carried`]});
				if(carriedBlock){
					carriedBlock.teleport({x:player.location.x+viewDX,y:player.location.y+viewDY+1.5,z:player.location.z+viewDZ},carriedBlock.dimension,0,0,true);
					let checkPlayer = this.getNearestPlayerLimitedDistance(carriedBlock);										
					if(!checkPlayer){
						carriedBlock.removeTag("carried");
						continue;
					}
					if(checkPlayer.isSneaking){
						carriedBlock.removeTag("carried");
						continue;
					}
					let carriedItem = checkPlayer.getComponent("inventory").container.getItem(checkPlayer.selectedSlot);
					if(!carriedItem){
						carriedBlock.removeTag("carried");
						continue;
					}
					if(!carriedItem.typeId.toLowerCase().includes("levitation")){
						carriedBlock.removeTag("carried");
						continue;
					}
					player.onScreenDisplay.setActionBar("§cThe Gravity Gun May Not\n    Pick up and Place\n   the Correct Blocks");
				}
				let thrownBlock = this.getGravityGunEntity({tags:[`${player.name},gg`],excludeTags:[`carried`]});
				if(thrownBlock){
					if(this.getNearestBlock(thrownBlock)){
						thrownBlock.dimension.fillBlocks(thrownBlock.location, thrownBlock.location, MinecraftBlockTypes.get(thrownBlock.getTags()[1]));
						thrownBlock.triggerEvent("despawn");
					}
				}				
			}			
		},1);

		//////////////////////////////////
		//GRAVITY GUN USED, CARRY AND SHOOT
		//////////////////////////////////
		world.events.itemUse.subscribe((eventData)=>{
			let player = eventData.source;
			let itemId = eventData.item.typeId;
			let rotationX = player.getRotation().x;
			if(rotationX>=83) return;
			if(!itemId.includes("levitation")) return;
			let oldCarriedBlock = this.getGravityGunEntity({type:"pg:block",tags:[`${player.name},gg`,`carried`]});
			if(oldCarriedBlock){
				oldCarriedBlock.removeTag("carried");
				oldCarriedBlock.applyImpulse({x:player.getViewDirection().x*3,y:player.getViewDirection().y*3,z:player.getViewDirection().z*3});
				return;
			}
			let playerBlockViewDirection = player.getBlockFromViewDirection({includeLiquidBlock:false, includePassableBLocks:true, maxDistance:8});		
			if(!playerBlockViewDirection) return;
			let blockItem = this.blockToItem(playerBlockViewDirection);			
			let carriedBlock = player.dimension.spawnEntity("pg:block",player.location);
			carriedBlock.addTag(`${player.name},gg`);
			carriedBlock.addTag(`${playerBlockViewDirection.typeId}`);
			carriedBlock.addTag(`carried`);
			carriedBlock.runCommandAsync(`replaceitem entity @s slot.weapon.mainhand 0 ${blockItem.typeId}`);
			carriedBlock.dimension.fillBlocks(playerBlockViewDirection.location, playerBlockViewDirection.location, MinecraftBlockTypes.get("minecraft:air"));		
		});
	}

	static getNearestBlock(carriedBlock){
		let carriedPos = carriedBlock.location;
		let carriedDim = carriedBlock.dimension;
		let blockXPos = carriedDim.getBlock({x:carriedPos.x+0.3,y:carriedPos.y,z:carriedPos.z});
		let blockYPos = carriedDim.getBlock({x:carriedPos.x,y:carriedPos.y+0.3,z:carriedPos.z});
		let blockZPos = carriedDim.getBlock({x:carriedPos.x,y:carriedPos.y,z:carriedPos.z+0.3});
		let blockXNeg = carriedDim.getBlock({x:carriedPos.x-0.3,y:carriedPos.y,z:carriedPos.z});
		let blockYNeg = carriedDim.getBlock({x:carriedPos.x,y:carriedPos.y-0.3,z:carriedPos.z});
		let blockZNeg = carriedDim.getBlock({x:carriedPos.x,y:carriedPos.y,z:carriedPos.z-0.3});

		if(!blockXPos.typeId.toLowerCase().includes("air")){
			return blockXPos;
		}
		if(!blockYPos.typeId.toLowerCase().includes("air")){
			return blockYPos;
		}
		if(!blockZPos.typeId.toLowerCase().includes("air")){
			return blockZPos;
		}
		if(!blockXNeg.typeId.toLowerCase().includes("air")){
			return blockXNeg;
		}
		if(!blockYNeg.typeId.toLowerCase().includes("air")){
			return blockYNeg;
		}
		if(!blockZNeg.typeId.toLowerCase().includes("air")){
			return blockZNeg;
		}
	}

	static getNearestPlayerLimitedDistance(gravityGunEntity){
		let portalLocation = gravityGunEntity.location;
		let portalDimension = gravityGunEntity.dimension;
		let nearestPlayerQuery = {closest:1,maxDistance:5,location:portalLocation,families:["player"]};
		let nearestPlayer = Array.from(portalDimension.getEntities(nearestPlayerQuery));
		return nearestPlayer[0];
	}

	static getGravityGunEntity(query){
		let gravityGunEntity = Array.from(world.getDimension("overworld").getEntities(query));
		return gravityGunEntity[0];
	}

	static blockToItem(block){
		try{
			let blockId = block.typeId;
			//Change concrete powder to match item id
			if(blockId.includes(`powder`)) blockId = 'minecraft:concrete_powder';
			//Change slabs to match item id
			if(blockId.includes(`stone_slab`) && !blockId.includes(`double_`)){
				blockId = blockId.split(':')[0] + ':' + 'double_' + blockId.split(':')[1];	
			}
			//Change sign to match item id
			if(blockId.includes(`_standing`)) blockId = blockId.replace(/_standing/g,'');
			if(blockId==`minecraft:standing_sign`) blockId = "minecraft:oak_sign";
			if(blockId.includes('dark') && blockId.includes('sign')) blockId = "minecraft:dark_oak_sign";
			
			return new ItemStack(ItemTypes.get(blockId),1);
		}catch(e){	
			console.warn(e)
		}
	}
	
}