import {expect} from "chai"
import {TokenList} from "../../../source/types/tokenlist.mjs";


describe('TokenList', function () {

    describe('.toString()', function () {
        let tokenList = new TokenList()
        let result = tokenList.toString();

        it('should return a string', function () {
            expect(result).to.be.a('string');
        });

        it('set and remove return a string', function () {
            expect(result).to.be.a('string');
        });


    });


    describe('init with string iterable', function () {

        it('new TokenList(' + typeof a + ') throw TypeError ', function () {

            let tokens = ["abc", "def", "ghi"]
            let list = new TokenList(tokens);
            expect(list.toString()).is.equal("abc def ghi");
        });

    });

    describe('init with iterable without string values', function () {

        it('new TokenList(' + typeof a + ') throw TypeError ', function () {
            let tokens = ["abc", 4, "ghi"]
            expect(() => new TokenList(tokens)).to.throw(TypeError);
        });

    });

    describe('init values', function () {

        [
            // current, expected, typerror
            ['test1', "test1", false],
            ['test1 test2', "test1 test2", false],
            [undefined, "", false],
            [null, undefined, true],
            [parseInt("a"), undefined, true], // NaN
            [() => {
            }, undefined, true],
            [2, undefined, true],
            [false, undefined, true],
            [true, undefined, true],
            [4.5, undefined, true],
            [{}, undefined, true],
            [["1", "2", "3"], '1 2 3', false], // iterable strings
            [[1, 2, 3], undefined, true],
            [Symbol("foo"), false, true],
        ].forEach(function (data) {

            let a = data.shift()
            let b = data.shift()
            let c = data.shift()

            if (c === true) {
                it('new TokenList(' + typeof a + ') throw TypeError ', function () {
                    expect(() => new TokenList(a)).to.throw(TypeError);
                });
            } else {
                it('new TokenList(' + typeof a + ') should return ' + b, function () {
                    expect(new TokenList(a).toString()).is.equal(b)
                });

            }

        });

    });

    describe('iterator protocol', function () {

        let list;
        it('.add(' + "second" + ') should return TokenList', function () {
            list = new TokenList("start");
            expect(list.getIterator()).to.be.an('object');
        });

        it('.add(' + "second" + ') should return TokenList', function () {
            list = new TokenList("start end");
            expect([...list]).to.be.an('array');
            expect([...list]).to.be.an('array').to.include('start').to.include('end');
        });


    });

    describe('.entries()', function () {

        let list;
        it('.entries() should return Array', function () {
            list = new TokenList("start");
            expect(list.entries()).to.be.an('array');
        });

        it('.entries() should return Array', function () {
            list = new TokenList("start end").entries();
            expect(list).to.be.an('array').to.include('start').to.include('end');
        });


    });

    describe('.forEach()', function () {

        let list;
        it('.forEach() should iterate over tokenlist', function () {
            list = new TokenList("aaa bbb ccc ddd eee fff");

            let result = ""
            list.forEach((a) => {
                result += "!" + a + "!";
                expect(a).to.be.an('string');
            });
            expect(result).is.equal("!aaa!!bbb!!ccc!!ddd!!eee!!fff!")
        });

        it('.entries() should return Array', function () {
            list = new TokenList("start end").entries();
            expect(list).to.be.an('array').to.include('start').to.include('end');
        });


    });

    describe('contains values', function () {
        let list
        it('new TokenList(start, middle end) should contain middle', function () {
            list = new TokenList("start middle end");
            expect(list.contains('start')).to.be.true;
            expect(list.contains('middle')).to.be.true;
            expect(list.contains('end')).to.be.true;
            expect(list.contains(['end', 'start', 'middle'])).to.be.true;
        });

        it('new TokenList(start, middle end) should not contain xyz', function () {
            list = new TokenList("start middle end");
            expect(list.contains('xyz')).to.be.false;
            expect(list.contains(['end', 'start', 'middle', 'xyz'])).to.be.false;
        });

        it('new TokenList(start, middle end) should not contain undefined null NaN', function () {
            list = new TokenList("start middle end");
            expect(list.contains(undefined)).to.be.false;
            expect(list.contains(parseInt("a"))).to.be.false; // NaN
            expect(list.contains(null)).to.be.false; // NaN
        });
    })

    describe('toggle values', function () {
        let list
        it('new TokenList(start middle end).toggle(new-value) should contain new-value', function () {
            list = new TokenList("start middle end");
            expect(list.toggle('new-value').toString()).is.equal("start middle end new-value");
        });

        it('new TokenList(start middle end).toggle(middle) should not contain middle', function () {
            list = new TokenList("start middle end");
            expect(list.toggle('middle').toString()).is.equal("start end");
        });

        it('new TokenList().toggle() should ...', function () {
            expect(new TokenList("abc def ghi").toggle("def xyz").toString()).to.equal("abc ghi xyz");
        });

        it('new TokenList().toggle() should ...', function () {
            expect(new TokenList("abc def ghi").toggle(["abc", "xyz"]).toString()).to.equal("def ghi xyz");
        });

        it('new TokenList().toggle() should ...', function () {
            expect(new TokenList("abc def ghi").toggle(undefined).toString()).to.equal("abc def ghi");
        });

    })

    describe('manipulate values', function () {

        let list

        it('result TokenList("' + "start" + '") should be "' + "start" + '"', function () {
            list = new TokenList("start");
            expect(list.toString()).is.equal("start")
        });

        it('.add(' + "second" + ') should return TokenList', function () {
            list = new TokenList("start");
            expect(list.add("second")).to.be.an.instanceof(TokenList);
        });

        it('.add(' + "second" + ').toString() should return "start second" ', function () {
            list = new TokenList("start");
            expect(list.add("second").toString()).is.equal("start second");
        });

        it('.add(' + "second third" + ').toString() should return "start second third" ', function () {
            list = new TokenList("start");
            expect(list.add("second third").toString()).is.equal("start second third");
        });

        it('.add(' + "[second,third]" + ').toString() should return "start second third" ', function () {
            list = new TokenList("start");
            expect(list.add(["second", "third"]).toString()).is.equal("start second third");
        });


        it('.clear().toString() should "" ', function () {
            list = new TokenList("start");
            expect(list.add(["second", "third"]).clear().toString()).is.equal("");
        });


        it('new TokenList("start second third end").remove(' + "second" + ') should return TokenList', function () {
            list = new TokenList("start second third end");
            expect(list.remove("second")).to.be.an.instanceof(TokenList);
        });

        it('new TokenList("start second third end").remove(' + "second" + ').toString() should return "start third end" ', function () {
            list = new TokenList("start second third end");
            expect(list.remove("second").toString()).is.equal("start third end");
        });

        it('new TokenList("start second third end").remove(' + "second third" + ').toString() should return "start end" ', function () {
            list = new TokenList("start second third end");
            expect(list.remove("second third").toString()).is.equal("start end");
        });

        it('new TokenList("start second third end").remove(' + "[second,third]" + ').toString() should return "start end" ', function () {
            list = new TokenList("start second third end");
            expect(list.remove(["second", "third"]).toString()).is.equal("start end");
        });

        it('new TokenList("start second third end").replace(second, xyz).toString() should return "start xyz third end" ', function () {
            list = new TokenList("start second third end");
            expect(list.replace("second", "xyz")).to.be.instanceOf(TokenList);
            expect(list.toString()).is.equal("start xyz third end");
        });

        it('new TokenList("start second third end").replace(end, xyz).toString() should return "start second third xyz" ', function () {
            list = new TokenList("start second third end");
            expect(list.replace("end", "xyz")).to.be.instanceOf(TokenList);
            expect(list.toString()).is.equal("start second third xyz");
        });


    });


});

