import * as mc from '@minecraft/server';
import Vec3 from '../../modules/Vec3.js';
import scoresSystem from '../scores/scoresSystem.js';
import entityManager from './entityManager.js';
import dimensionSystem from '../dimension/dimensionSystem.js';
import Commands from '../commands/runCommand.js';

export default class entitySystem extends entityManager {
    constructor() {
        super();
        this.dimension = dimensionSystem;
    };
    
    runCommand(command, target, errorDef) {
        return Commands.run(command, target, errorDef);
    }
    
    runCommands(command, target) {
        return Commands.runList(command, target);
    }
    
    runCommandFromViewEntity(selector, command, source, view) {
        let execute_list = range(1,4).map(i => {
            let r1 = Math.pow(view.length/2, 2) + 0.25;
            let r2 = r1 - view.width;
            let rx = r1 - view.width / 2;
            let pos = i > 2 ? `^^${rx * -Math.pow(-1,i)}^8.1` : `^${rx * -Math.pow(-1,i)}^^8.1`
            return `at @a[name="${source.nameTag}"] positioned ${pos} if entity @s[r=${r1},rm=${r2}] `
        }).join("");
        
        // `at @a positioned ^63.75^^8.1 if entity @s[r=64.25,rm=63.25] `
        // `at @a positioned ^-63.75^^8.1 if entity @s[r=64.25,rm=63.25] `
        // `at @a positioned ^^63.75^8.1 if entity @s[r=64.25,rm=63.25] `
        // `at @a positioned ^^-63.75^8.1 if entity @s[r=64.25,rm=63.25] `
        
        // /execute as @e[type=creeper] 
        // run kill
        
        let command_list = [
            `execute as ${selector} `,
            execute_list,
            `run ${command}`
        ].join("")
        
        return this.runCommand(command_list, source);

    }
    
    scores(entity, score) {
        return new scoresSystem(entity, score);
    }
    
    getRotation(target) {
        return {
            x: Math.asin(-target?.getViewDirection().y) * 180 / Math.PI,
            y: -Math.atan2(target?.getViewDirection().x, target?.getViewDirection().z) * 180 / Math.PI
        }
    }
    
    getEntityName(entity) {
        try {
            return this.runCommand(`testfor @s`, entity).victim.join();
        } catch(e) {}
    }
    
    getLc(target) {
        let rad = Math.PI / 180;
        let rot = this.getRotation(target);
        return {
            x: -Math.sin(rot.y * rad) * Math.cos(rot.x * rad),
            y: -Math.sin(rot.x * rad),
            z: Math.cos(rot.y * rad) * Math.cos(rot.x * rad)
        }
    }
    
    getLc2(x,y) {
        let rad = Math.PI / 180;
        let rot = {
            x: x,
            y: y
        };
        return {
            x: -Math.sin(rot.y * rad) * Math.cos(rot.x * rad),
            y: -Math.sin(rot.x * rad),
            z: Math.cos(rot.y * rad) * Math.cos(rot.x * rad)
        }
    }
    
    getHandItem(holder) {
        let item = holder.getComponent("inventory").container.getItem(holder.selectedSlot);
        if (item !== undefined) {
            return item;
        } else {
            return {
                typeId: null,
                amount: null,
                data: null,
                nameTag: null
            }
        }
    }
    
    shoot(source, projectileId, power, offset) {
        let lc = this.getLc(source);
        let pos = source.location;
        
        let entity = source.dimension.spawnEntity(projectileId, new Vec3(pos.x + offset[0] + lc.x * 2, pos.y + offset[1] + lc.y * 2, pos.z + offset[2] + lc.z * 2).Position());
        entity.applyImpulse(new Vec3(lc.x * power * 10, lc.y * power * 10, lc.z * power * 10).Vector());
    }
    
    getEntitiesFromQuery(options = null, dimension = null) {
        let _index = new Array();
        
        if (dimension === null) {
            this.dimension.get(`all`).forEach(dimensions => {
                _index = dimensions.getEntities(options);
            })
            return _index;
        } else {
            return dimension.getEntities(options);
        }
    }
    
    getEntitiesAtPosition(lengths, pos) {
        let min = parseInt(lengths.split("..")[0]);
        let max = parseInt(lengths.split("..")[1]);
        let entitiesIndex = new Array();
        this.dimension.get(`all`).forEach(dimension => {
            let entitiesGet = dimension.getEntitiesAtBlockLocation(new Vec3(Math.floor(pos[0]), Math.floor(pos[1]), Math.floor(pos[2])).PositionFloor());
            let entitiesLength = (max === undefined ? (entitiesGet.length > min ? true : false) : (entitiesGet.length > min && entitiesGet.length < max ? true : false));
            if (entitiesLength) {
                entitiesIndex = new Array(...entitiesGet);
            }
        })
        return entitiesIndex;
    }
    
    getEntitiesFromViewVector(source, distance) {
        let query = {};
        if (distance !== undefined) {
            query.maxDistance = distance;
        }
        return source.getEntitiesFromViewDirection(query);
    }
    
    getBlockFromViewVector(source, distance, obj) {
        let query = {};
        if (distance !== undefined) {
            query.maxDistance = distance;
        }
        if (obj !== undefined) {
            query.includeLiquidBlocks = obj.liquid;
            query.includePassableBlocks = obj.passable;
        }
        return source.getBlockFromViewDirection(query)?.block;
    }
    
}

