import * as chai from 'chai';
import {chaiDom} from "../../../util/chai-dom.mjs";
import {initJSDOM} from "../../../util/jsdom.mjs";

let expect = chai.expect;
chai.use(chaiDom);

let Dataset;

function buildDatasource(id, payload) {
    const ds = document.createElement('monster-datasource-dom');
    ds.id = id;
    ds.innerHTML = `<script type="application/json">${JSON.stringify(payload)}</script>`;
    return ds;
}

describe('Dataset writeBack sanitizer', function () {

    before(async function () {
        await initJSDOM();
        await import("element-internals-polyfill").catch(() => {});
        await import("../../../../source/components/datatable/datasource/dom.mjs");
        const mod = await import("../../../../source/components/datatable/dataset.mjs");
        Dataset = mod['DataSet'];
    });

    beforeEach(() => {
        const mocks = document.getElementById('mocks');
        mocks.innerHTML = '';
    });

    afterEach(() => {
        const mocks = document.getElementById('mocks');
        mocks.innerHTML = '';
    });

    it('sanitizes data before write and avoids side effects', async function () {
        const mocks = document.getElementById('mocks');
        const ds = buildDatasource('ds-sanitize', [{}]);
        mocks.appendChild(ds);

        const dataset = document.createElement('monster-dataset');
        expect(dataset).is.instanceof(Dataset);

        dataset.setOption('datasource.selector', '#ds-sanitize');
        dataset.setOption('mapping.data', '');

        const initial = {name: '', email: 'a@b', tags: []};
        dataset.setOption('data', initial);

        dataset.setOption('writeBack.transformer', 'call:sanitize');
        dataset.setOption('writeBack.callbacks', {
            sanitize: (obj) => {
                for (const [key, value] of Object.entries(obj)) {
                    if (value === '' || value === null || value === undefined) {
                        delete obj[key];
                        continue;
                    }
                    if (Array.isArray(value) && value.length === 0) {
                        delete obj[key];
                    }
                }
                return obj;
            },
        });

        mocks.appendChild(dataset);

        await new Promise((resolve) => setTimeout(resolve, 30));
        await dataset.write();

        expect(ds.data[0]).deep.equal({email: 'a@b'});

        const internal = dataset.getInternalUpdateCloneData();
        expect(internal.data).deep.equal({name: '', email: 'a@b', tags: []});
        expect(initial).deep.equal({name: '', email: 'a@b', tags: []});
    });

    it('uses original data when sanitizer returns undefined', async function () {
        const mocks = document.getElementById('mocks');
        const ds = buildDatasource('ds-undefined', [{}]);
        mocks.appendChild(ds);

        const dataset = document.createElement('monster-dataset');
        dataset.setOption('datasource.selector', '#ds-undefined');
        dataset.setOption('mapping.data', '');

        const initial = {name: '', email: 'a@b'};
        dataset.setOption('data', initial);

        dataset.setOption('writeBack.transformer', 'call:noop');
        dataset.setOption('writeBack.callbacks', {
            noop: () => undefined,
        });

        mocks.appendChild(dataset);

        await new Promise((resolve) => setTimeout(resolve, 30));
        await dataset.write();

        expect(ds.data[0]).deep.equal({name: '', email: 'a@b'});
    });

});
