"use strict";

import {expect} from "chai"
import {Transformer} from "../../../source/data/transformer.mjs";
import {getLocaleOfDocument} from "../../../source/dom/locale.mjs";
import {Embed} from "../../../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() localize commands', function () {


        const isNode = typeof global === 'object' && '[object global]' === global.toString.call(global);


        [
            ['datetimeformat', "2023-02-04 08:02:01", "Feb 4, 2023, 08:02:01", "4 Feb 2023, 08:02:01"],
            ['datetimeformat:long:short', "2023-02-04 08:02:01", "February 4, 2023 at 08:02", "4 February 2023 at 08:02"],
            ['datetimeformat:short:short', "2023-02-04 08:02:01", "2/4/23, 08:02", "04/02/2023, 08:02"],
            ['currency', "EUR0", "€0.00", "€0.00"],
//            ['currency:1:2', "EUR14.25", "€14.3", "€14.2"],
            ['currency', "EUR14.25", "€14.25", "€14.25"],
            ['datetime', "2023-02-14 14:12:10", "2/14/2023, 14:12:10","14/02/2023, 14:12:10"],
            ['datetime', "2023-02-14 08:02:01", "2/14/2023, 08:02:01","14/02/2023, 08:02:01"],
            ['date', "2023-02-14", "02/14/2023","14/02/2023"],


        ].forEach(function (data) {

            // https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/124


            let a = data.shift() // command
            let b = data.shift() // value
            let c = data.shift() // expected result node    
            let d = data.shift() // expected result browser    

            const expected = isNode ? c : d

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

    });


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

        [
            ['equals:a', "a", true],
            ['equals:a', "b", false],
            ['equals:3', 3, true],
            ['equals:3', 6, false],
            ['equals:on', true, true],
            ['equals:true', true, true],
            ['equals:on', false, false],
            ['equals:true', false, false],
            ['equals:off', false, true],
            ['equals:false', false, true],
            ['equals:off', false, true],
            ['equals:false', true, false],
            ['equals:3', 3, true],
            ['equals:3', 6, false],
            ['equals:undefined', undefined, true],
            ['equals:undefined', 3, false],
            ['equals:null', null, true],
            ['equals:null', 3, false],
            ['equals:3', 6, false],
            ['has-entries', {}, false],
            ['has-entries', {a: 4}, true],
            ['has-entries', [], false],
            ['has-entries', "", false],
            ['has-entries', [1, 2, 3], true],
            ['has-entries', [1], true],
            ['has-entries', ["1"], true],
            ['has-entries', [true], true],
            ['contains:x', "asd wxd sdf", true],
            ['contains:x', "asd wd sdf", false],
            ['contains:b', ["a", "b", "c"], true],
            ['contains:x', ["a", "b", "c"], false],
            ['isundefined', "a", false],
            ['isundefined', null, false],
            ['isundefined', undefined, true],
            ['isnull', "a", false],
            ['isnull', null, true],
            ['isset', null, false],
            ['isset', undefined, false],
            ['isset', "", true],
            ['isnumber', "a", false],
            ['isnumber', 4, true],
            ['isnumber', 4.5, true],
            ['isinteger', 4.5, false],
            ['isinteger', 4, true],
            ['isfloat', 5.6, true],
            ['isfloat', 5, false],
            ['isobject', 4, false],
            ['isobject', {}, true],
            ['isarray', [{}], true],
            ['isarray', "a", false],
            ['not', true, false],
            ['not', false, true],
            ['map:a=4:b=5:c=6', "a", "4"],
            ['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:undefined:bool', undefined, false],
            ['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: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'],
            ['set-toggle:c', 'a b c', 'a b'],
            ['set-toggle:c', 'a b', 'a b c'],
            ['set-set:c', 'a b', 'a b c'],
            ['set-set:c', 'a b c', 'a b c'],
            ['set-remove:c', 'a b c', 'a b'],
            ['set-toggle:c:,', 'a,b,c', 'a,b'],
            ['set-toggle:c:,', 'a,b', 'a,b,c'],
            ['set-set:c:,', 'a,b', 'a,b,c'],
            ['set-set:c:,', 'a,b,c', 'a,b,c'],
            ['set-remove:c:,', 'a,b,c', 'a,b'],
            ['set-toggle:c,d:,', 'a,b,c', 'a,b,d'],
            ['set-toggle:c,d:,', 'a,b,c,d', 'a,b'],
            ['set-toggle:c,d:,', 'a,b', 'a,b,c,d'],
            ['set-set:c,d:,', 'a,b', 'a,b,c,d'],
            ['set-set:c,d:,', 'a,b,c', 'a,b,c,d'],
            ['set-remove:c:,', 'a,b,c', 'a,b'],

        ].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(c).to.be.eql(r, "Transformer.run(" + JSON.stringify(a) + ").run(" + JSON.stringify(b) + ") should return " + JSON.stringify(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);
            });
        })
    })


});
