/// <reference path="../Action.ts" />
/// <reference path="../Rule.ts" />
/// <reference path="../Rulebook.ts" />
class ActionGoThrough extends Action {
    public static check = new Rulebook<ActionGoThrough>("Check Going Through");
    public static carry = new Rulebook<ActionGoThrough>("Carry out Going Through");

    public constructor (actor : Thing, ...nouns : Array<any>) {
        super(actor, ...nouns);
        this.requiresNoun = true;
        this.requiresVisibility = true;
    }

    public getCommandText () {
        return "go through " + (<Door> this.getDoor()).getPrintedName();
    }

    public getDoor () : Door {
        return this.getNoun(0);
    }

    public static checkLocked = ActionGoThrough.check.createAndAddRule({
        firstPriority : Rule.PRIORITY_HIGHEST,
        priority : Rule.PRIORITY_HIGHEST,
        name : "Check Going Through - Is it locked?",
        code : async (runner: RulebookRunner<ActionGoThrough>) => {
            let actor = runner.noun.actor;
            let door = <Door> runner.noun.getDoor();
            let isPlayer = WorldState.isPlayer(actor);

            if (door.locked) {
                let actorThings = actor.getEnclosed();
                if (actorThings.includes(door.key)) {
                    if (isPlayer) {
                        Elements.CurrentTurnHandler.printAsContent(new Say(Say.Mention(door), " is locked, but you can unlock it with ", Say.Mention(door.key), ". Do you want to unlock it?"));
                        if (!(await Controls.askForConsent())) {
                            return false;
                        }
                    }
                    door.locked = false;
                } else {
                    if (isPlayer) {
                        runner.noun.say.add("It's locked, and you don't have the key to unlock it...");
                    }
                    // TODO: Reconsider whether taking a turn on failed open checks is good.
                    return false;
                }
            }
        }
    });

    public static carryGoThrough = ActionGoThrough.check.createAndAddRule({
        name: "Carry Going Through - Go Through!",
        code: async (runner: RulebookRunner<ActionGoThrough>) => {
            let actor = runner.noun.actor;
            let door = <Door> runner.noun.getDoor();
            let isPlayer = WorldState.isPlayer(actor);

            if (isPlayer) {
                runner.noun.say.add("You go through ", Say.Mention(door), ".");

                if (actor.isPlayer()) {
                    WorldState.rememberRoom(actor.getRoom(), door.destination);
                }
            } else {
                let oldRoom = actor.getRoom();
                let playerRoom = WorldState.player.getRoom();
                if (oldRoom == playerRoom) {
                    runner.noun.say.add(Say.Mention(actor), " goes through ", Say.Mention(door), ".");
                } else {
                    runner.noun.say.add(Say.Mention(actor), " arrives through ", Say.Mention(door), ".");
                }
            }

            door.destination.place(actor);
        }
    });
}

Elements.HyperlinkHandler.HyperlinkingRulebook.addRule(new Rule(
    {
        name : "Hyperlink - Go through",
        firstPriority : Rule.PRIORITY_HIGHEST,
        code : (rulebook : RulebookRunner<Thing>) => {
            let thing = <Thing> rulebook.noun;

            if (thing instanceof Door && thing.isVisibleTo(WorldState.player)) {
                Elements.HyperlinkHandler.addAvailableAction("Go through", new ActionGoThrough(WorldState.player, thing));
            }
        }
    }
));