'use strict';

import * as chai from 'chai';
import {Data} from "../../../../source/dom/resource/data.mjs";
import {DataUrl} from "../../../../source/types/dataurl.mjs";
import {ID} from "../../../../source/types/id.mjs";
import {chaiDom} from "../../../util/chai-dom.mjs";
import {cleanupDOMFromTesting, initMutationObserverForTesting} from "../../../util/cleanupdom.mjs";
import {initJSDOM} from "../../../util/jsdom.mjs";

let expect = chai.expect;

chai.use(chaiDom);

const validDataURL = 'https://example.test/data.json';
const allowedOrigins = ['https://example.test'];

let html1 = `

`;


describe('Data', function () {

    let fetchReference, returnStatus, mutationobserver, addedNodes = [];


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

    beforeEach(() => {

        initMutationObserverForTesting()

        returnStatus = 200;
        fetchReference = globalThis['fetch'];
        globalThis['fetch'] = function (url, options) {

            if (!url) throw new Error('missing url')

            return new Promise((resolve, reject) => {
                resolve({
                    text: function () {
                        return JSON.stringify({
                            a: "test"
                        })
                    },
                    status: returnStatus
                });
            })

        };


    })

    afterEach(() => {
        globalThis['fetch'] = fetchReference;
        cleanupDOMFromTesting();
    })

    describe('Data()', function () {
        it('setEventTypes()', function (done) {

            const data = new Data({
                src: validDataURL,
                allowedOrigins
            });

            data.connect().available().then(() => {
                done()
            }).catch(e => done(e));

        })

        it('rejects executable script types', function () {

            const scriptCount = document.querySelectorAll('script').length;
            const data = new Data({
                src: new DataUrl('console.log(1);', 'text/javascript').toString(),
                type: 'text/javascript'
            });

            expect(() => data.connect()).to.throw('unsupported data resource type');
            expect(document.querySelectorAll('script')).to.have.length(scriptCount);

        })

        it('rejects remote origins by default', function () {

            const scriptCount = document.querySelectorAll('script').length;
            const data = new Data({
                src: 'https://cdn.example/data.json'
            });

            expect(() => data.connect()).to.throw('data resource origin not allowed');
            expect(document.querySelectorAll('script')).to.have.length(scriptCount);

        })

        it('allows configured remote origins', function (done) {

            const data = new Data({
                src: 'https://cdn.example/data.json',
                allowedOrigins: ['https://cdn.example']
            });

            data.connect().available().then(() => {
                expect(data.isConnected()).to.be.true;

                done();
            }).catch(e => done(e));

        })

        it('does not expose fetch errors in DOM attributes', function (done) {

            globalThis['fetch'] = function () {
                return Promise.reject(new Error('token=secret'));
            };

            const data = new Data({
                src: validDataURL,
                id: 'data-error',
                allowedOrigins
            });

            data.connect();

            setTimeout(() => {
                try {
                    const script = document.getElementById('data-error');

                    expect(script.hasAttribute('data-monster-error')).to.be.false;

                    done();
                } catch (e) {
                    done(e);
                }
            }, 0);

        })
    });

    describe('External Data', () => {

        let id = new ID('data').toString();
        let server, data, url = 'https://example.test/layzr.json';

        beforeEach(() => {

            data = new Data({
                src: url,
                id: id,
                allowedOrigins
            });

        });

        it('data is not connected', () => {
            expect(data.isConnected()).to.be.false;
        })

        it('connect and check availability', (done) => {

            data.connect().available().then(() => {
                expect(data.isConnected(), 'isConnected 1').to.be.true;
                expect(document.querySelector('[type="application/json"]'), 'exists 1').to.exist;

                const e = document.getElementById(id).parentElement;


                document.getElementById(id).remove();

                expect(data.isConnected(), 'isConnected 2').to.be.false;
                expect(document.querySelector('[type="application/json"]'), 'exists 2').not.to.exist;

                data.connect().available().then(() => {
                    expect(data.isConnected(), 'isConnected 3').to.be.true;
                    expect(document.querySelector('[type="application/json"]'), 'exists 3').to.exist;

                    document.getElementById(id).remove();
                    expect(document.querySelector('[type="application/json"]'), 'exists 4').not.to.exist;
                    expect(data.isConnected(), 'isConnected 4').to.be.false;

                    done()
                }).catch(e => done(e));


            }).catch(e => done(e));


        });


    });


});
