"use strict";

import {expect} from "chai"
import {Transformer} from "../../../../application/source/data/transformer.mjs";
import {Embed} from "../../../../application/source/i18n/providers/embed.mjs";
import {initJSDOM} from "../../util/jsdom.mjs";

describe('Transformer', function () {

    before(function (done) {

        let promises = []
        promises.push(initJSDOM());
        if (!globalThis['crypto']) {
            promises.push(import("@peculiar/webcrypto").then(m => {
                globalThis['crypto'] = new m.Crypto();
                return true;
            }))
        }

        Promise.all(promises).then(() => {
            done()
        });

    });

    describe('Transformer.run()', function () {

        [
            ['map:a=4:b=5:c=6', "a", "4"],
            ['date', "2023-02-14", "14.2.2023"],
            ['year', "2023-02-14", 2023],
            ['month', "2023-02-14", 2],
            ['day', "2023-02-14", 14],
            ['weekday', "2023-02-14", 2],
            ['minutes', "2023-02-14 06:12:21", 12],
            ['seconds', "2023-02-14 06:12:21", 21],
            ['hours', "2023-02-14 06:12:21", 6],
            ['time', "2023-02-14 06:12:21", "06:12:21"],
            ['timestamp', "2023-02-14", 1676332800000],
            ['concat:a.b.c:test:a.b.d', {a: {b: {c: 4, d: 6}}}, "4test6"],
            ['concat:a.b.c:\\ \\ :a.b.d', {a: {b: {c: 4, d: 6}}}, "4  6"],
            ['concat:a.b.c:,:a.b.d', {a: {b: {c: 4, d: 6}}}, "4,6"],
            ['concat:a.b.c:,:\\ :a.b.d', {a: {b: {c: 4, d: 6}}}, "4, 6"],
            ['??:a', null, 'a'],
            ['??:a', undefined, 'a'],
            ['??:a', 'true', 'true'],
            ['??:a', false, false],
            [' if:a: ', false, undefined], // without \\
            [' if:a:\\ ', false, " "],
            [' if:a:\\ ', true, "a"],
            ['default:yes', null, 'yes'],
            ['default:yes', undefined, 'yes'],
            ['default:1:bool', undefined, true],
            ['default:on:bool', undefined, true],
            ['default:true:bool', undefined, true],
            ['default:yes:bool', undefined, true],
            ['default:undefined:bool', undefined, false],
            ['default:false:bool', undefined, false],
            ['default:1:int', undefined, 1],
            ['default:1:string', undefined, '1'],
            ['first-key', {a: 1, c: 3, b: 2}, 1],
            ['last-key', {a: 1, c: 3, b: 2}, 3],
            ['nth-last-key:0', {a: 1, c: 3, b: 2}, 3],
            ['nth-last-key:1', {a: 1, c: 3, b: 2}, 2],
            ['nth-last-key:2', {a: 1, c: 3, b: 2}, 1],
            ['nth-key:2', {a: 1, b: 2, c: 3}, 3],
            ['nth-key:0', {c: 3, a: 1, b: 2}, 1],
            ['nth-key:2', {a: 1, c: 3, b: 2}, 3],
            ['prefix:Hello\\ ', 'test', "Hello test"],
            ['tojson', {a: 4}, "{\"a\":4}"],
            ['prefix:a\\\\: ', 'test', "a\\test"],
            ['prefix:a\\ ', 'test', "a test"],
            ['static:abc:a:b:x', "test", "abc:a:b:x"],
            ['tolowercase', "A:b:Cse4", "a:b:cse4"],
            ['toupper', "A:b:Cse4", "A:B:CSE4"],
            ['tostring', 5, "5"],
            ['tostring', [1, 2, 3, {}], "1,2,3,[object Object]"],
            ['tointeger', "5", 5],
            ['trim', " 5 ", "5"],
            ['trim', " a", "a"],
            ['trim', " ", ""],
            ['rawurlencode', "üöä", "%C3%BC%C3%B6%C3%A4"],
            ['call:testcallback:4:5:6', "test", "test456"],
            ['plain', 't<br>est', "test"],
            ['if:a:b', true, "a"],
            ['if:a:b', 'on', "a"],
            ['if:a:b', 'true', "a"],
            ['if:a:b', 'false', "b"],
            ['if:a:b', 9, "a"],
            ['if:a:b', '', "b"],
            ['if:a:b', undefined, "b"],
            ['if:a:b', false, "b"],
            ['ucfirst', 'car', "Car"],
            ['ucfirst', 'cAr', "CAr"],
            ['default:test', 'a', "a"],
            ['default:test', undefined, "test"],
            ['fromjson', '{}', {}],
            ['fromjson', '{"a":1}', {a: 1}],
            ['ucwords', 'cAr runs', "CAr Runs"],
            ['tointeger', '6', 6],
            ['length', 'test', 4],
            ['to-base64', 'Hello World!', "SGVsbG8gV29ybGQh"],
            ['from-base64', 'SGVsbG8gV29ybGQh', "Hello World!"],
            ['to-base64', 'test', "dGVzdA=="],
            ['from-base64', "dGVzdA==", 'test'],
            ['prefix:a', 'test', "atest"],
            ['suffix:a', 'test', "testa"],
            ['index:a', {a: 4}, 4],
            ['index:2', [2, 4, 7], 7],
            ['index:x:test', [2, 4, 7], 'test'],
            ['path:a.b.c', {a: {b: {c: 4}}}, 4],
            ['path:a.b.d', {a: {b: {c: 4}}}, undefined],
            ['index:a', new Map().set('a', 5), 5],
            ['substring:2:4', 'abcdefghijklmnop', 'cdef'],
            ['nop', 'abcdefghijklmnop', 'abcdefghijklmnop'],

        ].forEach(function (data) {

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

            it('Transformer.run(' + JSON.stringify(a) + ').run(' + JSON.stringify(b) + ') should return ' + JSON.stringify(c), function () {
                let t = new Transformer(a);

                t.setCallback('testcallback', function (a, b, c, d) {
                    return a + b + c + d;
                });

                const r = t.run(b);
                expect(r).to.be.eql(c);
            });
        });

    });

    describe('Transformer.run() throws Error', function () {

        [
            ['tolowercase', []],
            ['tolowercase', {}],
            ['tolowercase', 4.5],
            ['toupper', true],
            ['toupper', 5],
            ['tointeger', "a"],
            ['trim', 5],
            ['trim', true],
            ['trim', {}],
            ['trim', []],
            ['rawurlencode', []],
            ['if:a:b', {}],
            ['ucwords', {}],
            ['ucwords', false],
            ['ucwords', 4],
            ['path:a.b.c', "", 4],
            ['tointeger', {}],
            ['base64', {}],
            ['fromjson', ''],
            ['prefix', {}],
            ['suffix', {}],
            ['index', "test"],
            ['xxxxxx', "test"], // unsupported command
        ].forEach(function (data) {

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

            it('Transformer.run(' + JSON.stringify(a) + ').run(' + JSON.stringify(b) + ') should throw Error ', function () {
                let t = new Transformer(a);
                expect(() => t.run(b)).to.throw(Error)
            });
        });

    });


    describe('new Transformer().run("uniqid")', function () {
        it('should return String', function () {
            let t = new Transformer('uniqid');
            expect(t.run("")).to.be.a('string');
        });

    });

    describe('new Transformer().run("default:eyJiIjoxfQ==:object")', function () {
        it('should return Object', function () {
            let t = new Transformer('default:eyJiIjoxfQ==:object');
            expect(t.run(undefined)).to.eql({b: 1});
        });

    });


    describe('new Transformer()', function () {
        it('should return instanceof Transformer', function () {
            expect(new Transformer("")).to.instanceOf(Transformer);
        });

        it('should return instanceof Transformer', function () {
            expect(new Transformer("suffix:abc")).to.instanceOf(Transformer);
        });

        it('false as argument should throw TypeError', function () {
            expect(() => {
                new Transformer(false)
            }).to.throw(TypeError);
        });

        it('object as argument should throw TypeError', function () {
            expect(() => {
                new Transformer({})
            }).to.throw(TypeError);
        });
    });


    describe('i18n', function () {

        let html1 = `
<div id="mock-translations"></div>
<script type="application/json" data-monster-role="translations">
    {
        "test1": "xyz",
        "test3": {
            "other": "xyz"
        }
    }
</script>  
`;

        beforeEach((done) => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = html1;
            let elem = document.getElementById('mock-translations');
            Embed.assignTranslationsToElement(elem).then((o) => {
                done()
            })


        })

        afterEach(() => {
            let mocks = document.getElementById('mocks');
            mocks.innerHTML = "";
        })

        before(function (done) {
            initJSDOM().then(() => {
                done()
            });
        });

        [
            ['i18n:test1', "", "xyz"],
            ['i18n:', "test1", "xyz"], // key by value
            ['i18n::', "test1", "xyz"], // key by value no default
            ['i18n::eee', "test2", "eee"], // key by value with default
            ['i18n::ddd', "test2", "ddd"], // key by value and default

        ].forEach(function (data) {

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

            it('should transform(' + a + ').run(' + b + ') return ' + JSON.stringify(c), function () {
                const t = new Transformer(a);
                expect(t.run(b)).to.be.eql(c);
            });
        })
    })


});