"use strict";

import {expect} from "chai"
import {diff} from "../../../source/data/diff.mjs";
import {Queue} from "../../../source/types/queue.mjs";

describe('Diff', function () {

    describe('test to datasets', function () {

        var obj1, obj2;

        beforeEach(() => {
            obj1 = [
                {
                    "id": 1,
                    "name": "test"
                },
                {
                    "id": 2,
                    "name": "test2"
                }
            ]

            obj2 = [
                {
                    "id": 1,
                    "name": "test"
                },
                {
                    "id": "3",
                    "name": "test2"
                }
            ]

        });

        it('should return the difference between two datasets', function () {
            let d = diff(obj1, obj2);
            expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["1","id"],"first":{"value":2,"type":"number"},"second":{"value":"3","type":"string"}}]');
        });
        
        
    })
    
    describe('Diff special cases', function () {

        var obj1, obj2;

        beforeEach(() => {
            obj1 = {
                "count": 1,
                "reason": null,
                "info": "test",
                "exchange": []
            };
            obj2 = {
                "count": 2,
                "reason": null,
                "info": undefined,
                "exchange": []
            };

        });

        it('Diff value with null ', function () {
            let d = diff(obj1, obj2);
            expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["count"],"first":{"value":1,"type":"number"},"second":{"value":2,"type":"number"}},{"operator":"delete","path":["info"],"first":{"value":"test","type":"string"}}]');
        });

        it('Diff identical value with null ', function () {
            let d = diff(obj1, obj1);
            expect(JSON.stringify(d)).is.equal('[]');
        });


    })

    const date1 = new Date;

    // https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
    const date2 = Date.parse('01 Jan 1970 00:00:00 GMT');
    const date3 = Date.parse('04 Dec 1995 00:12:00 GMT'); // Number
    const date4 = Date.parse('04 Dec 1995 00:12:01 GMT'); // Number

    const date5 = new Date(Date.parse('04 Dec 1995 00:12:01 GMT')); // Date
    const date6 = new Date(Date.parse('04 Dec 1995 00:12:02 GMT')); // Date

    const hiddenKey = Symbol("hidden");
    class HiddenState {
        constructor(value) {
            this[hiddenKey] = value;
        }

        get value() {
            return this[hiddenKey];
        }

        getClone() {
            return new HiddenState(this.value);
        }
    }

    [
        [
            [],
            [],
            '[]'
        ],

        [
            {},
            {},
            '[]'
        ],

        [
            {
                a: [],
                b: {}
            },
            {
                a: [],
                b: {}
            },
            '[]'
        ],

        [
            {},
            {
                a: new Queue()
            },
            '[{"operator":"add","path":["a"],"second":{"value":{"data":[]},"type":"object","instance":"Queue"}}]'
        ],

        [
            {
                a: {
                    b: 1
                },
                c: {
                    d: 2
                }
            },
            {
                a: {
                    e: 3
                },
                f: {
                    d: 2
                }
            },
            '[{"operator":"delete","path":["a","b"],"first":{"value":1,"type":"number"}},{"operator":"add","path":["a","e"],"second":{"value":3,"type":"number"}},{"operator":"delete","path":["c"],"first":{"value":{"d":2},"type":"object","instance":"Object"}},{"operator":"add","path":["f"],"second":{"value":{"d":2},"type":"object","instance":"Object"}}]'
        ],

        [
            {
                a: date1,
                c: date4
            },
            {
                a: date2,
                b: date3
            },
            '[{"operator":"update","path":["a"],"first":{"value":"' + date1.toISOString() + '","type":"object","instance":"Date"},"second":{"value":0,"type":"number"}},{"operator":"delete","path":["c"],"first":{"value":818035921000,"type":"number"}},{"operator":"add","path":["b"],"second":{"value":818035920000,"type":"number"}}]'
        ],

        [
            {
                a: date5
            },
            {
                b: date6
            },
            '[{"operator":"delete","path":["a"],"first":{"value":"1995-12-04T00:12:01.000Z","type":"object","instance":"Date"}},{"operator":"add","path":["b"],"second":{"value":"1995-12-04T00:12:02.000Z","type":"object","instance":"Date"}}]'
        ],
        [
            {
                a: date1
            },
            {
                a: date1
            },
            '[]'
        ],
        [
            {
                a: new HiddenState("a")
            },
            {
                a: new HiddenState("b")
            },
            '[{"operator":"update","path":["a"],"first":{"value":{},"type":"object","instance":"HiddenState"},"second":{"value":{},"type":"object","instance":"HiddenState"}}]'
        ],
        [
            {},
            {
                a: date3
            },
            '[{"operator":"add","path":["a"],"second":{"value":818035920000,"type":"number"}}]'
        ],

        [
            {
                a: date2
            },
            {
                a: date3
            },
            '[{"operator":"update","path":["a"],"first":{"value":0,"type":"number"},"second":{"value":818035920000,"type":"number"}}]'
        ],

        [
            {
                a: 1
            },
            {
                a: 2
            },
            '[{"operator":"update","path":["a"],"first":{"value":1,"type":"number"},"second":{"value":2,"type":"number"}}]'
        ],

        [
            {
                a: 1
            },
            {
                x: 1
            },
            '[{"operator":"delete","path":["a"],"first":{"value":1,"type":"number"}},{"operator":"add","path":["x"],"second":{"value":1,"type":"number"}}]'
        ],

        [
            {
                a: 1
            },
            {
                a: 2,
                x: 1
            },
            '[{"operator":"update","path":["a"],"first":{"value":1,"type":"number"},"second":{"value":2,"type":"number"}},{"operator":"add","path":["x"],"second":{"value":1,"type":"number"}}]'
        ],
        [
            {
                a: null
            },
            {},
            '[{"operator":"delete","path":["a"],"first":{"value":null,"type":"object"}}]'
        ],
        [
            {
                a: null
            },
            {
                a: null
            },
            '[]'
        ],
        [
            {},
            {
                a: null
            },
            '[{"operator":"add","path":["a"],"second":{"value":null,"type":"object"}}]'
        ], [
        {},
        {a: undefined},
        '[{"operator":"add","path":["a"],"second":{"type":"undefined"}}]'
    ]


    ].forEach(function (data) {

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


        it('Diff should result ' + c, function () {
            let d = diff(a, b);
            expect(JSON.stringify(d)).is.equal(c);
        });


    });

})
