package net.cobem.grizzly.habbohotel.wired;

import net.cobem.grizzly.Grizzly;
import net.cobem.grizzly.communication.EventRequest;
import net.cobem.grizzly.habbohotel.pathfinding.Position;
import net.cobem.grizzly.habbohotel.rooms.Room;
import net.cobem.grizzly.habbohotel.rooms.items.FloorItem;
import net.cobem.grizzly.habbohotel.sessions.Session;
import net.cobem.grizzly.habbohotel.wired.effects.ChangeState;
import net.cobem.grizzly.habbohotel.wired.effects.MoveAndRotate;
import net.cobem.grizzly.habbohotel.wired.effects.ShowMessage;
import net.cobem.grizzly.habbohotel.wired.effects.TransportUser;
import net.cobem.grizzly.habbohotel.wired.triggers.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WiredHandler {
    private Room Room;

    private List<FloorItem> Triggers = new ArrayList<>();
    private List<FloorItem> Effects = new ArrayList<>();
    private List<FloorItem> Conditions = new ArrayList<>();

    private Map<String, WiredObject> WiredClasses = new HashMap<>();

    private Map<Integer, String> WiredMovements = new HashMap<>();
    private Map<Integer, String> WiredRotations = new HashMap<>();

    public WiredHandler(Room mRoom){
        this.Room = mRoom;

        this.registerWired();
        this.registerWiredClasses();
        this.registerWiredMovements();
    }

    private void registerWired(){
        for(FloorItem Item : Room.getFloors().values()) {
            if (Item.getBase().Interaction.contains("wf_")) {
                if (Item.getBase().Interaction.contains("_act_")) {
                    Effects.add(Item);
                }
                else if(Item.getBase().Interaction.contains("_trg_")) {
                    Triggers.add(Item);
                }
                else{
                    Conditions.add(Item);
                }
            }
        }
    }

    private void registerWiredClasses() {
        WiredClasses.put(WiredType.TRIGGER_ENTERROOM, new OnEnterRoom());
        WiredClasses.put(WiredType.TRIGGER_SAYMESSAGE, new SayMessage());
        WiredClasses.put(WiredType.TRIGGER_STANDONFURNI, new WalksOnFurni());
        WiredClasses.put(WiredType.TRIGGER_STANDOFFFURNI, new WalksOffFurni());
        WiredClasses.put(WiredType.TRIGGER_CHANGEFURNISTATE, new ToggleFurniState());

        WiredClasses.put(WiredType.EFFECT_SENDALERT, new ShowMessage());
        WiredClasses.put(WiredType.EFFECT_CHANGEUSERPOSITION, new TransportUser());
        WiredClasses.put(WiredType.EFFECT_CHANGEFURNISTATE, new ChangeState());
        WiredClasses.put(WiredType.EFFECT_CHANGEITEMPOSITION, new MoveAndRotate());

    }

    private void registerWiredMovements() {
        WiredMovements.put(0, "none");
        WiredMovements.put(1, "random");
        WiredMovements.put(2, "vertical");
        WiredMovements.put(3, "horizontal");
        WiredMovements.put(4, "right");
        WiredMovements.put(5, "down");
        WiredMovements.put(6, "left");
        WiredMovements.put(7, "up");

        WiredRotations.put(0, "none");
        WiredRotations.put(1, "clockwise");
        WiredRotations.put(2, "counter-clockwise");
        WiredRotations.put(3, "random");
    }

    public boolean isEffect(FloorItem Item) {
        return Item.getBase().Interaction.contains("_act_");
    }

    public boolean isTrigger(FloorItem Item) {
        return Item.getBase().Interaction.contains("_trg_");
    }

    public boolean isCondition(FloorItem Item) {
        return Item.getBase().Interaction.contains("_cnd_");
    }

    public List<FloorItem> getWiredForInteraction(String Type) {
        List<FloorItem> Collection = new ArrayList<>();

        for(FloorItem Item : Room.getFloors().values()) {
            if (Item.getBase().Interaction.equals(Type)) {
                Collection.add(Item);
            }
        }

        return Collection;
    }

    public boolean onUserEnter(Session Session) {
        List<FloorItem> Triggers = getWiredForInteraction(WiredType.TRIGGER_ENTERROOM);

        for(FloorItem Item : Triggers) {
            for(FloorItem ItemOnTop : Room.getItemsAbove(Item)) {
                if(isEffect(ItemOnTop)) {
                    Grizzly.getHabboHotel().getInteractions().onTrigger(ItemOnTop.getBase().Interaction, Session, ItemOnTop, 2);
                }
            }
        }

        return true;
    }

    public boolean onUserWalkOnFurni(Session Session, FloorItem mItem) {
        boolean FoundItem = false;

        List<FloorItem> Triggers = getWiredForInteraction(WiredType.TRIGGER_STANDONFURNI);

        for(FloorItem Item : Triggers) {

            for(String ItemID : Item.ExtraData.split(";")) {
                if (mItem.ID == new Integer(ItemID)) {
                    FoundItem = true;
                    break;
                }
            }

            if (FoundItem) {
                for(FloorItem ItemOnTop : Room.getItemsAbove(Item)) {
                    if(isEffect(ItemOnTop)) {
                        Grizzly.getHabboHotel().getInteractions().onTrigger(ItemOnTop.getBase().Interaction, Session, ItemOnTop, 2);
                    }
                }
            }
        }

        return false;
    }

    public boolean onToggleFurniState(Session Session, FloorItem mItem) {
        boolean FoundItem = false;

        List<FloorItem> Triggers = getWiredForInteraction(WiredType.TRIGGER_CHANGEFURNISTATE);

        for(FloorItem Item : Triggers) {
            for(String ItemID : Item.ExtraData.split(";")) {
                if (mItem.ID == new Integer(ItemID)) {
                    FoundItem = true;
                    break;
                }
            }

            if (FoundItem) {
                for(FloorItem ItemOnTop : Room.getItemsAbove(Item)) {
                    if(isEffect(ItemOnTop)) {
                        Grizzly.getHabboHotel().getInteractions().onTrigger(ItemOnTop.getBase().Interaction, Session, ItemOnTop, 2);
                    }
                }
            }
        }

        return false;
    }

    public boolean onUserWalkOffFurni(Session Session, FloorItem mItem) {
        boolean FoundItem = false;

        List<FloorItem> Triggers = getWiredForInteraction(WiredType.TRIGGER_STANDOFFFURNI);

        for(FloorItem Item : Triggers) {

            for(String ItemID : Item.ExtraData.split(";")) {
                if (mItem.ID == new Integer(ItemID)) {
                    FoundItem = true;
                    break;
                }
            }

            if (FoundItem) {
                for(FloorItem ItemOnTop : Room.getItemsAbove(Item)) {
                    if(isEffect(ItemOnTop)) {
                        Grizzly.getHabboHotel().getInteractions().onTrigger(ItemOnTop.getBase().Interaction, Session, ItemOnTop, 2);
                    }
                }
            }
        }

        return false;
    }

    public boolean onUserTalk(Session Session, String Message) {
        List<FloorItem> Triggers = getWiredForInteraction(WiredType.TRIGGER_SAYMESSAGE);

        boolean TriggerHasErrors = true;

        for(FloorItem Item : Triggers) {

            if (!Message.equals(Item.ExtraData)) {
                continue;
            }

            for(FloorItem ItemOnTop : Room.getItemsAbove(Item)) {
                if(isEffect(ItemOnTop)) {
                    Grizzly.getHabboHotel().getInteractions().onTrigger(ItemOnTop.getBase().Interaction, Session, ItemOnTop, 2);
                }

                TriggerHasErrors = false;
            }
        }

        if (!TriggerHasErrors) {
            return true;
        }

        if (Triggers.size() == 0) {
            return false;
        }
        return false;
    }

    public void removeFurni(FloorItem Item) {
        String Str = Item.ID + ";";
        for(FloorItem mItem : Room.getFloors().values()) {
            if (mItem.ExtraData.contains(Str)) {
                mItem.ExtraData = mItem.ExtraData.replace(Str, "").trim();
                mItem.saveState();
            }
        }
    }

    public void saveWired(Session Session, FloorItem Item, EventRequest Message) {
        if (WiredClasses.containsKey(Item.getBase().Interaction)) {
            WiredClasses.get(Item.getBase().Interaction).save(Session, Item, Message);
        }
    }

    public Position calculateMovement(int MovementKey, Position CurrentPosition) {
        int X = 0;
        int Y = 0;

        String Movement = WiredMovements.get(MovementKey);

        switch(Movement) {
            case "random":
                Position Pos = Room.getModel().getRandomSquare();

                X = Pos.X;
                Y = Pos.Y;
            break;

            case "vertical":
                if (Grizzly.rand(0, 1) == 0) {
                    X = CurrentPosition.X;
                    Y = CurrentPosition.Y - 1;
                } else {
                    X = CurrentPosition.X;
                    Y = CurrentPosition.Y + 1;
                }
            break;

            case "horizontal":
                if (Grizzly.rand(0, 1) == 0) {
                    X = CurrentPosition.X + 1;
                    Y = CurrentPosition.Y;
                } else {
                    X = CurrentPosition.X - 1;
                    Y = CurrentPosition.Y;
                }
            break;

            case "up":
                X = CurrentPosition.X;
                Y = CurrentPosition.Y - 1;
            break;

            case "down":
                X = CurrentPosition.X;
                Y = CurrentPosition.Y + 1;
            break;

            case "right":
                X = CurrentPosition.X + 1;
                Y = CurrentPosition.Y;
            break;

            case "left":
                X = CurrentPosition.X - 1;
                Y = CurrentPosition.Y;
            break;
        }

        return new Position(X, Y, CurrentPosition.Z);
    }

    public int calculateRotation(int MovementKey, int CurrentRotation) {
        int Rotation = 0;

        String Movement = WiredRotations.get(MovementKey);

        switch(Movement) {
            case "clockwise":
                Rotation = CurrentRotation + 2;

                if (Rotation > 6) {
                    Rotation = 0;
                }
            break;

            case "counter-clockwise":
                Rotation = CurrentRotation - 2;

                if (Rotation < 0) {
                    Rotation = 6;
                }
            break;

            case "random":
                if (Grizzly.rand(0, 1) == 1) {
                    Rotation = CurrentRotation - 2;

                    if (Rotation < 0) {
                        Rotation = 6;
                    }
                } else {
                    Rotation = CurrentRotation + 2;

                    if (Rotation > 6) {
                        Rotation = 0;
                    }
                }
            break;
        }

        return Rotation;
    }
}
