package net.pietru.omni_power.blockevents;

import com.badlogic.gdx.utils.Array;
import finalforeach.cosmicreach.blockentities.BlockEntity;
import finalforeach.cosmicreach.blockevents.BlockEventArgs;
import finalforeach.cosmicreach.blockevents.ScheduledTrigger;
import finalforeach.cosmicreach.blockevents.actions.ActionId;
import finalforeach.cosmicreach.blockevents.actions.IBlockAction;
import finalforeach.cosmicreach.blocks.BlockPosition;
import finalforeach.cosmicreach.blockevents.BlockEventTrigger;
import finalforeach.cosmicreach.blocks.BlockState;
import finalforeach.cosmicreach.world.Zone;
import net.pietru.omni_power.OmniPower;
import net.pietru.omni_power.api.IPowerClient;
import net.pietru.omni_power.api.IPowerProducer;
import org.spongepowered.asm.mixin.Shadow;

import java.util.HashMap;
import java.util.Map;

@ActionId(id = OmniPower.MOD_ID+":power")
public class Power implements IBlockAction {
    public static boolean block_entities = false;

    public String triggerId;
    public String cable_group;
    public boolean self_run = true;

    public Power(){
        block_entities=OmniPower.block_entities;
    }

    @Override
    public void act(BlockEventArgs args) {
        Zone zone = args.zone;
        BlockPosition sourcePos = args.blockPos;
        boolean source_be = false;
        BlockEntity source_entity = null;
        if (block_entities){
            source_entity = sourcePos.chunk.getBlockEntity(sourcePos.localX,sourcePos.localY,sourcePos.localZ);
            source_be = (source_entity instanceof IPowerProducer);
            //System.out.println("SourceEntityID: "+ source_entity.getType().getId() +" BE: "+source_be);
        }
        Array<BlockPosition> power_transmitters = new Array<>();
        Array<BlockPosition> checked_blocks = new Array<>();
        Array<BlockPosition> unchecked_blocks = new Array<>();
        unchecked_blocks.add(sourcePos);
        while (unchecked_blocks.size>0){
            BlockPosition to_check = unchecked_blocks.get(0);
            unchecked_blocks.removeIndex(0);
            if (checked_blocks.contains(to_check,false) || to_check == null){
                continue;
            }
            checked_blocks.add(to_check);
            BlockState targetBlockState = to_check.getBlockState();
            if (targetBlockState==null || targetBlockState.stringId==null){
                continue;
            }
            if (to_check!=sourcePos || this.self_run){
                runTrigger(this.triggerId,to_check,args);
            }
            if (block_entities && source_be){
                BlockEntity target_entity = to_check.chunk.getBlockEntity(to_check.localX,to_check.localY,to_check.localZ);
                //if (target_entity!=null)
                //    System.out.println("TargetEntityID: "+target_entity.getType().getId()+" IsPowerClient: "+(target_entity instanceof IPowerClient));
                if (target_entity instanceof IPowerClient)
                    ((IPowerProducer)source_entity).send_to_client(target_entity);
            }
            if (targetBlockState.stringId.contains(this.cable_group)){
                power_transmitters.add(to_check);
                unchecked_blocks.addAll(get_touching_positions(zone,to_check,targetBlockState));
            }
        }
    }

    private void runTrigger(String triggerId, BlockPosition triggerPos, BlockEventArgs args) {

        Zone zone = args.zone;
        if (triggerPos != null) {
            BlockState targetBlockState = triggerPos.getBlockState();
            if (targetBlockState == null) {
                return;
            }

            BlockEventTrigger[] customTrigger = targetBlockState.getTrigger(triggerId);
            if (customTrigger == null) {
                return;
            }

            BlockEventArgs newArgs = new BlockEventArgs();
            newArgs.blockPos = triggerPos;
            newArgs.zone = zone;
            newArgs.srcBlockState = targetBlockState;
            newArgs.setSrcIdentity(args.getSrcIdentity());

            for (BlockEventTrigger t : customTrigger) {
                t.act(newArgs);
            }
        }
    }

    public Array<BlockPosition> get_touching_positions(Zone zone,BlockPosition pos,BlockState state){
        Array<BlockPosition> arr = new Array<>();
        BlockPosition side_pos;
        side_pos =  pos.getOffsetBlockPos(zone, 1, 0, 0);
        if (state.stringId.contains("xp_power") && block_has_dir_or_all(side_pos,"xm_power"))
            arr.add(side_pos);
        side_pos =  pos.getOffsetBlockPos(zone, -1, 0, 0);
        if (state.stringId.contains("xm_power") && block_has_dir_or_all(side_pos,"xp_power"))
            arr.add(side_pos);

        side_pos =  pos.getOffsetBlockPos(zone, 0, 1, 0);
        if (state.stringId.contains("yp_power") && block_has_dir_or_all(side_pos,"ym_power"))
            arr.add(side_pos);
        side_pos =  pos.getOffsetBlockPos(zone, 0, -1, 0);
        if (state.stringId.contains("ym_power") && block_has_dir_or_all(side_pos,"yp_power"))
            arr.add(side_pos);

        side_pos =  pos.getOffsetBlockPos(zone, 0, 0, 1);
        if (state.stringId.contains("zp_power") && block_has_dir_or_all(side_pos,"zm_power"))
            arr.add(side_pos);
        side_pos =  pos.getOffsetBlockPos(zone, 0, 0, -1);
        if (state.stringId.contains("zm_power") && block_has_dir_or_all(side_pos,"zp_power"))
            arr.add(side_pos);

        if (arr.size<=0) {
            arr.add(pos.getOffsetBlockPos(zone, 1, 0, 0));
            arr.add(pos.getOffsetBlockPos(zone, -1, 0, 0));

            arr.add(pos.getOffsetBlockPos(zone, 0, 1, 0));
            arr.add(pos.getOffsetBlockPos(zone, 0, -1, 0));

            arr.add(pos.getOffsetBlockPos(zone, 0, 0, 1));
            arr.add(pos.getOffsetBlockPos(zone, 0, 0, -1));
        }
        return arr;
    }

    public Boolean block_has_dir_or_all(BlockPosition pos, String dir){
        if (pos==null)
            return false;
        BlockState state = pos.getBlockState();
        if (state==null)
            return false;
        if (state.stringId==null)
            return false;
        return state.stringId.contains(dir) || state.stringId.contains("any_in_power") || !(
                        state.stringId.contains("xp_power")||
                        state.stringId.contains("xm_power")||
                        state.stringId.contains("yp_power")||
                        state.stringId.contains("ym_power")||
                        state.stringId.contains("zp_power")||
                        state.stringId.contains("zm_power")
                );
    }
}
