import { DOM, register, View, IBindingContext, createBindingContext, ViewController } from 'mframejs';
import { JSDOM } from 'jsdom';
import { RepeatAttribute } from '../../../src/mframejs/attribute/repeatAttribute';
import { ValueAttribute } from '../../../src/mframejs/attribute/valueAttribute';

let tempNode: any;
let repeatAttribute: RepeatAttribute;
let bindingContext: IBindingContext;



describe('repeatAttribute "a of arrayObject"', () => {


    beforeAll(() => {
        const window = new JSDOM('').window;
        DOM.setConfig(window, window.document);
        register(ValueAttribute);
        tempNode = DOM.document.createElement('div');
        tempNode.setAttribute('repeat.for', 'obj of arrayObject');
        tempNode.innerHTML = `
            <input value.bind="obj.firstname"><br>
            @{obj.firstname}
            <div>@{obj.lastname}</div>
            <div>
                <span>@{obj.age}</span>
            </div>`;
        repeatAttribute = new RepeatAttribute();
        bindingContext = createBindingContext({
            arrayObject: [
                {
                    firstname: 'firstname0',
                    lastname: 'lastname0',
                    age: 0
                },
                {
                    firstname: 'firstname1',
                    lastname: 'lastname1',
                    age: 1
                }, {
                    firstname: 'firstname2',
                    lastname: 'lastname2',
                    age: 2
                }, {
                    firstname: 'firstname3',
                    lastname: 'lastname3',
                    age: 3
                }, {
                    firstname: 'firstname4',
                    lastname: 'lastname4',
                    age: 4
                }, {
                    firstname: 'firstname5',
                    lastname: 'lastname5',
                    age: 5
                }, {
                    firstname: 'firstname6',
                    lastname: 'lastname6',
                    age: 6
                }, {
                    firstname: 'firstname7',
                    lastname: 'lastname7',
                    age: 7
                }, {
                    firstname: 'firstname8',
                    lastname: 'lastname8',
                    age: 8
                }, {
                    firstname: 'firstname9',
                    lastname: 'lastname9',
                    age: 9
                }]
        });
        repeatAttribute.$bindingContext = bindingContext;
        View.cleanTemplate(tempNode); // we we get rid of empty space nodes
        repeatAttribute.$element = tempNode;
        repeatAttribute.$attribute = tempNode.getAttributeNode('repeat.for');
        repeatAttribute.$controller = ({
            getView() {
                return new ViewController(null, null);
            }
        } as any);

    });



    it('call created', () => {
        expect(repeatAttribute.created()).toBe(undefined);
    });



    it('call attached', () => {
        DOM.document.body.appendChild(tempNode);
        expect(repeatAttribute.attached()).toBe(undefined);
    });



    it('test elements correct rows are created', async () => {

        expect(DOM.document.body.children.length).toBe(10);
        for (let i = 0; i < 10; i++) {
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[i].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[i].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[i].children[3].children[0].innerHTML).toBe('' + i);
        }
    });



    it('test arrayObject.reverse()', async () => {
        bindingContext.$context.arrayObject.reverse();
        expect(DOM.document.body.children.length).toBe(10);
        expect(bindingContext.$context.arrayObject[0].firstname).toBe('firstname9');
        await DOM.waitFor(50);
        for (let i = 9, y = 0; i > -1; i-- , y++) {
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[y].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[y].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[y].children[3].children[0].innerHTML).toBe('' + i);
        }
    });



    it('test arrayObject = null', async () => {
        bindingContext.$context.arrayObject = 0;
        await DOM.waitFor(0);
        expect(DOM.document.body.children.length).toBe(0);
    });


    it('test set back default', async () => {
        bindingContext.$context.arrayObject = [
            {
                firstname: 'firstname0',
                lastname: 'lastname0',
                age: 0
            },
            {
                firstname: 'firstname1',
                lastname: 'lastname1',
                age: 1
            }, {
                firstname: 'firstname2',
                lastname: 'lastname2',
                age: 2
            }, {
                firstname: 'firstname3',
                lastname: 'lastname3',
                age: 3
            }, {
                firstname: 'firstname4',
                lastname: 'lastname4',
                age: 4
            }, {
                firstname: 'firstname5',
                lastname: 'lastname5',
                age: 5
            }, {
                firstname: 'firstname6',
                lastname: 'lastname6',
                age: 6
            }, {
                firstname: 'firstname7',
                lastname: 'lastname7',
                age: 7
            }, {
                firstname: 'firstname8',
                lastname: 'lastname8',
                age: 8
            }, {
                firstname: 'firstname9',
                lastname: 'lastname9',
                age: 9
            }];

        expect(DOM.document.body.children.length).toBe(10);
        expect(bindingContext.$context.arrayObject[0].firstname).toBe('firstname0');
        for (let i = 0; i < 10; i++) {
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[i].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[i].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[i].children[3].children[0].innerHTML).toBe('' + i);
        }
    });



    it('test arrayObject.reverse()', async () => {
        bindingContext.$context.arrayObject.reverse();
        expect(DOM.document.body.children.length).toBe(10);
        expect(bindingContext.$context.arrayObject[0].firstname).toBe('firstname9');
        await DOM.waitFor(50);
        for (let i = 9, y = 0; i > -1; i-- , y++) {
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[y].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[y].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[y].children[3].children[0].innerHTML).toBe('' + i);
        }
    });


    it('test arrayObject = bindingContext.$context.arrayObject.slice()', async () => {
        bindingContext.$context.arrayObject = bindingContext.$context.arrayObject.slice();
        expect(DOM.document.body.children.length).toBe(10);
        expect(bindingContext.$context.arrayObject[0].firstname).toBe('firstname9');
        await DOM.waitFor(0);
        for (let i = 9, y = 0; i > -1; i-- , y++) {
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[y].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[y].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[y].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[y].children[3].children[0].innerHTML).toBe('' + i);
        }
    });


    it('test bindingContext.$context.arrayObject.slice().reverse()', async () => {
        bindingContext.$context.arrayObject = bindingContext.$context.arrayObject.slice().reverse();
        expect(DOM.document.body.children.length).toBe(10);
        expect(bindingContext.$context.arrayObject[0].firstname).toBe('firstname0');
        for (let i = 0; i < 10; i++) {
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect((DOM.document.body.children[i].childNodes[2] as any).data.trim()).toBe('firstname' + i);
            expect((DOM.document.body.children[i].children[0] as any).value).toBe('firstname' + i);
            expect(DOM.document.body.children[i].children[2].innerHTML).toBe('lastname' + i);
            expect(DOM.document.body.children[i].children[3].children[0].innerHTML).toBe('' + i);
        }
    });

    // todo add more

    it('detach', async () => {
        repeatAttribute.detached();
    });


    it('check i removed all', async () => {
        await DOM.waitFor(0);
        expect(DOM.document.body.children.length).toBe(0);
    });



});

