// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { compileGrammarToNFA } from "../src/nfaCompiler.js";
import { matchNFA } from "../src/nfaInterpreter.js";
import {
    Grammar,
    createStringPart,
    createWildcardPart,
} from "../src/grammarTypes.js";

describe("Wildcard Loop Behavior", () => {
    it("should match single-token wildcard", () => {
        // Pattern: show $(location:string) weather
        // Input: show peoria weather
        const grammar: Grammar = {
            alternatives: [
                {
                    parts: [
                        createStringPart(["show"]),
                        createWildcardPart("location", "string"),
                        createStringPart(["weather"]),
                    ],
                    value: {
                        type: "object",
                        value: [
                            {
                                type: "property",
                                key: "location",
                                value: { type: "variable", name: "location" },
                            },
                        ],
                    },
                },
            ],
        };

        const nfa = compileGrammarToNFA(grammar, "test-single-token");
        const tokens = ["show", "peoria", "weather"];
        const result = matchNFA(nfa, tokens);

        expect(result.matched).toBe(true);
        expect(result.actionValue?.location).toBe("peoria");
    });

    it("should match multi-token wildcard", () => {
        // Pattern: show $(location:string) weather
        // Input: show des moines weather
        const grammar: Grammar = {
            alternatives: [
                {
                    parts: [
                        createStringPart(["show"]),
                        createWildcardPart("location", "string"),
                        createStringPart(["weather"]),
                    ],
                    value: {
                        type: "object",
                        value: [
                            {
                                type: "property",
                                key: "location",
                                value: { type: "variable", name: "location" },
                            },
                        ],
                    },
                },
            ],
        };

        const nfa = compileGrammarToNFA(grammar, "test-multi-token");
        const tokens = ["show", "des", "moines", "weather"];
        const result = matchNFA(nfa, tokens);

        expect(result.matched).toBe(true);
        expect(result.actionValue?.location).toBe("des moines");
    });

    it("should match two wildcards with multi-token values", () => {
        // Pattern: play $(track:string) by $(artist:string)
        // Input: play kodachrome by paul simon
        const grammar: Grammar = {
            alternatives: [
                {
                    parts: [
                        createStringPart(["play"]),
                        createWildcardPart("track", "string"),
                        createStringPart(["by"]),
                        createWildcardPart("artist", "string"),
                    ],
                    value: {
                        type: "object",
                        value: [
                            {
                                type: "property",
                                key: "track",
                                value: { type: "variable", name: "track" },
                            },
                            {
                                type: "property",
                                key: "artist",
                                value: { type: "variable", name: "artist" },
                            },
                        ],
                    },
                },
            ],
        };

        const nfa = compileGrammarToNFA(grammar, "test-two-wildcards");
        const tokens = ["play", "kodachrome", "by", "paul", "simon"];
        const result = matchNFA(nfa, tokens);

        expect(result.matched).toBe(true);
        expect(result.actionValue?.track).toBe("kodachrome");
        expect(result.actionValue?.artist).toBe("paul simon");
    });

    it("should match wildcard at end consuming all remaining tokens", () => {
        // Pattern: show $(location:string)
        // Input: show des moines iowa
        const grammar: Grammar = {
            alternatives: [
                {
                    parts: [
                        createStringPart(["show"]),
                        createWildcardPart("location", "string"),
                    ],
                    value: {
                        type: "object",
                        value: [
                            {
                                type: "property",
                                key: "location",
                                value: { type: "variable", name: "location" },
                            },
                        ],
                    },
                },
            ],
        };

        const nfa = compileGrammarToNFA(grammar, "test-wildcard-at-end");
        const tokens = ["show", "des", "moines", "iowa"];
        const result = matchNFA(nfa, tokens);

        expect(result.matched).toBe(true);
        expect(result.actionValue?.location).toBe("des moines iowa");
    });
});
