import chai = require("chai");
const expect = chai.expect;
import "mocha";
import AntlrStepParser from "../../src/_infra/AntlrStepParser";
import Action from "../../src/domain/Action";
import InteractionFactory from "../../src/domain/InteractionFactory";
import Question from "../../src/domain/Question";
import SequenceEvaluator from "../../src/domain/SequenceEvaluator";
import StepFactory from "../../src/domain/StepFactory";

describe("Domain - SequenceEvaluator", () => {

    const stepParser = new AntlrStepParser();
    const stepFactory = new StepFactory(stepParser);

    describe("Evaluator", () => {
        let evaluator: SequenceEvaluator;
        const stepList = [];

        before("create evaluator", () => {
            const stepTextList = [
                "(clickSearchBar typeProductName clickOnSearchButton) or (clickSearchBar typeProductName pressEnterKey)",
                "addProductToBasket (if 'asksForWaranty' closeWarantyModal) clickShowBasketButton clickOrderButton if 'Does everything went ok' OK else NOK",
            ];
            const webSiteId = "1";

            evaluator = new SequenceEvaluator(webSiteId);
            return stepFactory.createStep("myStep", stepTextList[0], []).then((step) => {
                stepList.push(step);
                evaluator.addStep(step);
                return;
            }).then(() => {
                return stepFactory.createStep("myStep", stepTextList[1], []);
            }).then((step) => {
                stepList.push(step);
                evaluator.addStep(step);
            });
        });

        describe("evaluate a sequence that do not start the step ", () => {
            it("should have an entering action and not continuing action", () => {
                const interactions = [InteractionFactory.parseInteraction("start")];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([new Action("clickSearchBar")]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList).to.eql([]);
                    expect(evaluation.notValidatedStepList.length).eql(2);
                    expect(evaluation.notValidatedStepList.map((s) => s.expression)).to.eql(stepList.map((s) => s.expression ));
                });
            });
        });

        describe("evaluate a not finished step", () => {
            it("should have a continuing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([new Action("typeProductName")]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList).to.eql([]);
                    expect(evaluation.notValidatedStepList.length).eql(2);
                    expect(evaluation.notValidatedStepList.map((s) => s.expression)).to.eql(stepList.map((s) => s.expression ));
                });
            });
        });

        describe("evaluate a sequence leading to the finishing action", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([new Action("clickOnSearchButton"), new Action("pressEnterKey")]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList).to.eql([]);
                    expect(evaluation.notValidatedStepList.length).eql(2);
                    expect(evaluation.notValidatedStepList.map((s) => s.expression)).to.eql(stepList.map((s) => s.expression ));
                });
            });
        });

        describe("evaluate a sequence that finishes a step", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("clickOnSearchButton"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([new Action("addProductToBasket")]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList[0].expression).to.eql(stepList[0].expression);
                    expect(evaluation.notValidatedStepList.length).eql(1);
                    expect(evaluation.notValidatedStepList[0].expression).to.eql(stepList[1].expression);
                });
            });
        });

        describe("evaluate a sequence with an invalid action before finishing the step", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("wrongAction"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([new Action("clickSearchBar")]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList).to.eql([]);
                    expect(evaluation.notValidatedStepList.length).eql(2);
                    expect(evaluation.notValidatedStepList.map((s) => s.expression)).to.eql(stepList.map((s) => s.expression ));
                });
            });
        });

        describe("evaluate 'a sequence that finishes one step", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("clickOnSearchButton"),
                    InteractionFactory.parseInteraction("addFilter$1"),
                    InteractionFactory.parseInteraction("addFilter$2"),
                    InteractionFactory.parseInteraction("addProductToBasket"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([new Question("asksForWaranty")]);
                    expect(evaluation.validatedStepList[0].expression).to.eql(stepList[0].expression);
                    expect(evaluation.notValidatedStepList.length).eql(1);
                    expect(evaluation.notValidatedStepList[0].expression).to.eql(stepList[1].expression);
                });
            });
        });

        describe("evaluate a sequence that answers a question", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("clickOnSearchButton"),
                    InteractionFactory.parseInteraction("addFilter$1"),
                    InteractionFactory.parseInteraction("addFilter$2"),
                    InteractionFactory.parseInteraction("addProductToBasket"),
                    InteractionFactory.parseInteraction("asksForWaranty?true"),

            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([new Action("closeWarantyModal")]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList[0].expression).to.eql(stepList[0].expression);
                    expect(evaluation.notValidatedStepList.length).eql(1);
                    expect(evaluation.notValidatedStepList[0].expression).to.eql(stepList[1].expression);
                });
            });
        });

        describe("evaluate a sequence with a question leading to the last action", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("clickOnSearchButton"),
                    InteractionFactory.parseInteraction("addFilter$1"),
                    InteractionFactory.parseInteraction("addFilter$2"),
                    InteractionFactory.parseInteraction("addProductToBasket"),
                    InteractionFactory.parseInteraction("asksForWaranty?false"),

            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([new Action("clickShowBasketButton")]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList[0].expression).to.eql(stepList[0].expression);
                    expect(evaluation.notValidatedStepList.length).eql(1);
                    expect(evaluation.notValidatedStepList[0].expression).to.eql(stepList[1].expression);
                });
            });
        });

        describe("evaluate a sequence finishing all steps", () => {
            it("should have a finishing action", () => {
                const interactions = [
                    InteractionFactory.parseInteraction("start"),
                    InteractionFactory.parseInteraction("clickSearchBar"),
                    InteractionFactory.parseInteraction("typeProductName"),
                    InteractionFactory.parseInteraction("clickOnSearchButton"),
                    InteractionFactory.parseInteraction("addFilter$1"),
                    InteractionFactory.parseInteraction("addFilter$2"),
                    InteractionFactory.parseInteraction("addProductToBasket"),
                    InteractionFactory.parseInteraction("asksForWaranty?false"),
                    InteractionFactory.parseInteraction("clickShowBasketButton"),
                    InteractionFactory.parseInteraction("clickOrderButton"),
                    InteractionFactory.parseInteraction("Does everything went ok?true"),
                    InteractionFactory.parseInteraction("OK"),
            ];
                return evaluator.evaluate(interactions).then((evaluation) => {
                    expect(evaluation.enteringInteractionList).to.eql([]);
                    expect(evaluation.continuingActionList).to.eql([]);
                    expect(evaluation.finishingInteractionList).to.eql([]);
                    expect(evaluation.questionList).to.eql([]);
                    expect(evaluation.validatedStepList).to.eql(stepList);
                    expect(evaluation.notValidatedStepList).to.eql([]);
                });
            });
        });
    });

    describe("Evaluate", () => {
        let evaluator: SequenceEvaluator;
        const stepList = [];

        before("create evaluator", () => {
            const stepTextList = [
               "Click AddToBask",
            ];
            const sessionID = "1";

            evaluator = new SequenceEvaluator(sessionID);
            return stepFactory.createStep("myStep", stepTextList[0], []).then((step) => {
                stepList.push(step);
                evaluator.addStep(step);
                return;
            });
        });

        it ("match first action, then invalidated, then validate again", () => {
            const interactions = [
                InteractionFactory.parseInteraction("Click"),
                InteractionFactory.parseInteraction("AddToBask"),
            ];
            return evaluator.evaluate(interactions).then((evaluation) => {
                expect(evaluation.enteringInteractionList).to.eql([]);
                expect(evaluation.continuingActionList).to.eql([]);
                expect(evaluation.finishingInteractionList).to.eql([]);
                expect(evaluation.questionList).to.eql([]);
                expect(evaluation.validatedStepList).to.eql(stepList);
                expect(evaluation.notValidatedStepList).to.eql([]);
            });
        });

        it ("match first action, then invalidated, then validate again", () => {
            const interactions = [
                InteractionFactory.parseInteraction("start"),
                InteractionFactory.parseInteraction("Click"),
                InteractionFactory.parseInteraction("Search"),
                InteractionFactory.parseInteraction("Click"),
                InteractionFactory.parseInteraction("AddToBask"),
            ];
            return evaluator.evaluate(interactions).then((evaluation) => {
                expect(evaluation.enteringInteractionList).to.eql([]);
                expect(evaluation.continuingActionList).to.eql([]);
                expect(evaluation.finishingInteractionList).to.eql([]);
                expect(evaluation.questionList).to.eql([]);
                expect(evaluation.validatedStepList).to.eql(stepList);
                expect(evaluation.notValidatedStepList).to.eql([]);
            });
        });
    });

    describe("Evaluate", () => {
        let evaluator: SequenceEvaluator;
        const stepList = [];

        before("create evaluator", () => {
            const stepTextList = [
               'Search if "Can you see correct results" AddToBasket',
            ];
            const sessionID = "1";

            evaluator = new SequenceEvaluator(sessionID);
            return stepFactory.createStep("myStep", stepTextList[0],[]).then((step) => {
                stepList.push(step);
                evaluator.addStep(step);
                return;
            });
        });

        it ("match first action, then invalidated, then validate again", () => {
            const interactions = [
                InteractionFactory.parseInteraction("start"),
                InteractionFactory.parseInteraction("Click"),
                InteractionFactory.parseInteraction("Search$smartphone"),
            ];
            return evaluator.evaluate(interactions).then((evaluation) => {
                expect(evaluation.enteringInteractionList).to.eql([]);
                expect(evaluation.continuingActionList).to.eql([]);
                expect(evaluation.finishingInteractionList).to.eql([]);
                expect(evaluation.questionList).to.eql([new Question("Can you see correct results")]);
                expect(evaluation.validatedStepList).to.eql([]);
            });
        });

    });

    describe("Evaluate forbidden interaction", () => {
        let evaluator: SequenceEvaluator;
        const stepList = [];

        before("create evaluator that refuses action button2", () => {
            const sessionID = "1";

            evaluator = new SequenceEvaluator(sessionID);
            return stepFactory.createStep("myStep", 'button1[2] submit', ["button2"]).then((step) => {
                stepList.push(step);
                evaluator.addStep(step);
                return;
            });
        });

        it ("evaluate without button2", () => {
            const interactions = [
                InteractionFactory.parseInteraction("button1"),
                InteractionFactory.parseInteraction("button1"),
                InteractionFactory.parseInteraction("submit"),
            ];
            return evaluator.evaluate(interactions).then((evaluation) => {
                expect(evaluation.validatedStepList.length).to.eql(1);
                expect(evaluation.forbiddenInteractionList.length).to.eql(0);
                expect(evaluation.containsForbiddenInteraction).to.eql(false);

            });
        });

        it ("evaluate without button2", () => {
            const interactions = [
                InteractionFactory.parseInteraction("button1"),
                InteractionFactory.parseInteraction("button2"),

                InteractionFactory.parseInteraction("button1"),
                InteractionFactory.parseInteraction("submit"),
            ];
            return evaluator.evaluate(interactions).then((evaluation) => {
                expect(evaluation.validatedStepList.length).to.eql(1);
                expect(evaluation.forbiddenInteractionList.length).to.eql(1);
                expect(evaluation.containsForbiddenInteraction).to.eql(true);
            });
        });

    });
});
