/// <reference path="./Classes/Rulebook.ts" />
/// <reference path="./Classes/Rule.ts" />
/// <reference path="Classes/Things/Person.ts" />
/// <reference path="TurnSequence.ts" />
module EveryTurn {
    export var EveryTurn = new Rulebook("Every Turn");
    export var lastTurnTime = 10;
    export var lastPercentage = 1;
    export var minPercentage = 0.05;
    export var maxTurnDuration = 100;
    export var maxTurnsDead = 4;

    export var RunAIRule = EveryTurn.createAndAddRule({
        name : "Run NPC AI Rule",
        code : async function () {
            let allPeople = <Array<Person>> Thing.InsideRoomRelation.getAnyRightType(Person);
            let change;
            if (lastTurnTime > maxTurnDuration) {
                change = -0.1 * (lastTurnTime / maxTurnDuration);
            } else {
                change = +0.1 * (maxTurnDuration / lastTurnTime);
            }
            lastPercentage += change;
            lastPercentage = lastPercentage < minPercentage ? minPercentage : lastPercentage > 1 ? 1 : lastPercentage;
            function isAIAvailable (person : Person) {
                return (person != WorldState.player
                    && (
                        (person.getRoom() instanceof RoomRandom
                        && (<RoomRandom>person.getRoom()).placed)
                    )
                    && (person.lastActionTurn < WorldState.getCurrentTurn())
                    && (
                        person.lastActionTurn < (WorldState.getCurrentTurn() - maxTurnsDead) || Math.random() <= lastPercentage ||
                        person.getRoom() == WorldState.player.getRoom() || WorldState.player.getRoom().getConnectedRooms().includes(person.getRoom())
                    )
                );
            }


            let people = allPeople.filter(isAIAvailable);

            let t0 = performance.now();
            for (let i = 0; i < people.length; i++) {
                let person = people[i];
                if (person.getHealthOnScale() > 0) {
                    let action = await people[i].AI.execute();
                    let visible = people[i].isVisibleTo(WorldState.player); // Was the actor visible BEFORE doing the action?
                    if (action == undefined) action = new ActionWait(person);
                    let printValue: Say = await action.execute();

                    if (
                        (
                            visible ||
                            person.isVisibleTo(WorldState.player)
                        ) && printValue != undefined) {
                        Elements.CurrentTurnHandler.printAsContent(printValue);
                    }
                }
            }
            let t1 = performance.now();
            lastTurnTime = t1 - t0;
        }
    });

    export var regenerateBodyparts = EveryTurn.createAndAddRule({
        firstPriority: Rule.PRIORITY_LOWEST,
        priority: Rule.PRIORITY_MEDIUM,
        name: "Regenerate Bodyparts",
        code: function () {
            let bodyparts = <Array<Bodypart>> Thing.PartRelation.getAnyRightType(Bodypart);
            bodyparts.forEach(bodypart => {
                bodypart.regenerate();
            });
        }
    });

    export var incrementTurnCounterRule = EveryTurn.createAndAddRule({
        firstPriority: Rule.PRIORITY_LOWEST,
        priority: Rule.PRIORITY_LOWEST,
        name: "Increment Turn Counter",
        code: function () {
            WorldState.incrementWorldTurn();
        }
    });
}