import {
    isPrimitive,
    isBoolean,
    isString,
    isObject,
    isArray,
    isInstance,
    isFunction,
    isIterable,
    isInteger,
    isSymbol
} from "../../../source/types/is.mjs";


import {ID} from "../../../source/types/id.mjs"

import {expect} from "chai"
import {initJSDOM} from "../../util/jsdom.mjs";

describe('Is', function () {

    before(function (done) {

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


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

    });    
    
    describe('.isPrimitive()', function () {

        [
            ['test1', true],
            [undefined, true],
            [null, true],
            [() => {
            }, false],
            [2, true],
            [parseInt("a"), true],
            [false, true],
            [true, true],
            [4.5, true],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), true],
        ].forEach(function (data) {

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

            it('is.isPrimitive(' + typeof a + ') should return ' + b, function () {
                expect(isPrimitive(a)).is.equal(b)
            });
        });


    });
    describe('.isSymbol()', function () {

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, false],
            [parseInt("a"), false],
            [false, false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), true],
        ].forEach(function (data) {

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

            it('is.isSymbol(' + typeof a + ') should return ' + b, function () {
                expect(isSymbol(a)).is.equal(b)
            });
        });


    });

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

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, true],
            [parseInt("a"), false],
            [false, false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isInteger(' + typeof a + ') should return ' + b, function () {
                expect(isInteger(a)).is.equal(b)
            });
        });


    });

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

        [
            ['test1', true],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [parseInt("a"), false],
            [2, false],
            [false, false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], true],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isIterable(' + typeof a + ') should return ' + b, function () {
                expect(isIterable(a)).is.equal(b)
            });
        });


    });

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

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, false],
            [false, true],
            [parseInt("a"), false],
            [true, true],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isBoolean(' + typeof a + ') should return ' + b, function () {
                expect(isBoolean(a)).is.equal(b)
            });
        });


    });

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

        [
            ['test1', true],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, false],
            [false, false],
            [parseInt("a"), false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isString(' + typeof a + ') should return ' + b, function () {
                expect(isString(a)).is.equal(b)
            });
        });


    });

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

        [
            [new ID(), ID,  true],
            [new ID(), ()=>{},  false],
            ['test1', undefined, false],
            [undefined, undefined, false],
            [null, undefined, false],
            [() => {
            }, undefined, false],
            [2, undefined, false],
            [false, undefined, false],
            [parseInt("a"), undefined, false],
            [true, undefined, false],
            [4.5, undefined, false],
            [{}, undefined, false],
            [[1, 2, 3], undefined, false],
            [Symbol("foo"), undefined, false],
        ].forEach(function (data) {

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

            it('is.isInstance(' + JSON.stringify(a) + ') should return ' + typeof b, function () {
                expect(isInstance(a, b)).is.equal(c)
            });
        });
    });

    describe('.isInstanceExtended()', function () {
        class Base {}
        class Derived extends Base {}
        function AnotherClass() {}

        let baseInstance = new Base();
        let derivedInstance = new Derived();

        // Test cases
        const cases = [
            [() => {}, undefined, false,"function vs undefined"],
            [new ID(), ()=>{}, false, "ID instance vs function"],
            [new ID(), ID, true, "ID instance vs ID"],
            ['test1', undefined, false, "string vs undefined"],
            [undefined, undefined, false, "undefined vs undefined"],
            [null, undefined, false, "null vs undefined"],
            [2, undefined, false, "number vs undefined"],
            [false, undefined, false, "false vs undefined"],
            [parseInt("a"), undefined, false, "NaN vs undefined"],
            [true, undefined, false, "true vs undefined"],
            [4.5, undefined, false, "float vs undefined"],
            [{}, undefined, false, "object vs undefined"],
            [[1, 2, 3], undefined, false, "array vs undefined"],
            [Symbol("foo"), undefined, false, "symbol vs undefined"],
            [baseInstance, Base, true, "Base instance vs Base"],
            [derivedInstance, Base, true, "Derived instance vs Base"],
            [derivedInstance, Derived, true, "Derived instance vs Derived"],
            [baseInstance, Derived, false, "Base instance vs Derived"],
            [baseInstance, AnotherClass, false, "Base instance vs AnotherClass"],
            [derivedInstance, ()=>{}, false, "Derived instance vs function"],
            [new AnotherClass(), AnotherClass, true, "AnotherClass instance vs AnotherClass"],
        ];

        // Adding prototype modification test
        let protoModifiedInstance = new Base();
        Object.setPrototypeOf(protoModifiedInstance, Derived.prototype);
        cases.push(
            [protoModifiedInstance, Base, true, "Proto modified Base instance vs Base"], 
            [protoModifiedInstance, Derived, true, "Proto modified Base instance vs Derived"]
        );

        // Running the tests
        cases.forEach(function (data) {
            const a = data.shift();
            const b = data.shift();
            const c = data.shift();
            const d = data.shift();

            it('isInstance(' + JSON.stringify(a) + ', [Function]) should return ' + c, function () {
                
                if (isInstance(a, b)!==c) {
                    console.log(d)
                }
                
                expect(isInstance(a, b)).to.equal(c);
            });
        });
    });
    
    describe('.isObject()', function () {

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, false],
            [false, false],
            [parseInt("a"), false],
            [true, false],
            [4.5, false],
            [{}, true],
            [[1, 2, 3], false],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isObject(' + JSON.stringify(a) + ') should return ' + b, function () {
                expect(isObject(a)).is.equal(b)
            });
        });


    });


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

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, false],
            [2, false],
            [false, false],
            [parseInt("a"), false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], true],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isArray(' + typeof a + ') should return ' + b, function () {
                expect(isArray(a)).is.equal(b)
            });
        });
    });

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

        [
            ['test1', false],
            [undefined, false],
            [null, false],
            [() => {
            }, true],
            [2, false],
            [false, false],
            [parseInt("a"), false],
            [true, false],
            [4.5, false],
            [{}, false],
            [[1, 2, 3], false],
            [Symbol("foo"), false],
        ].forEach(function (data) {

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

            it('is.isFunction(' + typeof a + ') should return ' + b, function () {
                expect(isFunction(a)).is.equal(b)
            });
        });
    });

});

