import {expect} from "chai"

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

describe('initOptionsFromAttributes', () => {
    let element;
    let options;
    let initOptionsFromAttributes;

    before( function (done) {
         initJSDOM().then(() => {
            import("../../../../source/dom/util/init-options-from-attributes.mjs").then((m) => {
                initOptionsFromAttributes = m['initOptionsFromAttributes'];
                done();
            })
        })
    });

    beforeEach(() => {
        options = {url: "", key: {subkey: "", caseSensitive: true}};
        element = document.createElement('div');
    });

    it('should initialize options with matching attributes', () => {
        element.setAttribute('data-monster-option-url', 'https://example.com');
        element.setAttribute('data-monster-option-key-subkey', 'test');

        const result = initOptionsFromAttributes(element, options);

        expect(result.url).to.equal('https://example.com');
        expect(result.key.subkey).to.equal('test');
    });

    it('should not modify options without matching attributes', () => {
        const result = initOptionsFromAttributes(element, options);

        expect(result.url).to.equal('');
        expect(result.key.subkey).to.equal('');
    });

    it('should ignore attributes without the correct prefix', () => {
        element.setAttribute('data-some-option-url', 'https://example.com');

        const result = initOptionsFromAttributes(element, options);

        expect(result.url).to.equal('');
    });

    it('should ignore attributes with invalid option paths', () => {
        element.setAttribute('data-monster-option-nonexistent', 'value');

        const result = initOptionsFromAttributes(element, options);

        expect(result).to.deep.equal(options);
    });

    it('should apply mapping for a single attribute', () => {
        element.setAttribute('data-monster-option-url', 'example');
        const mapping = {
            'url': (value) => 'https://' + value + '.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('https://example.com');
    });

    it('should apply mapping for a nested attribute', () => {
        element.setAttribute('data-monster-option-key-subkey', '123');
        const mapping = {
            'key.subkey': (value) => parseInt(value, 10) * 2
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.key.subkey).to.equal("246");
    });

    it('should apply multiple mappings', () => {
        element.setAttribute('data-monster-option-url', 'example');
        element.setAttribute('data-monster-option-key-subkey', '123');
        const mapping = {
            'url': (value) => 'https://' + value + '.com',
            'key.subkey': (value) => parseInt(value, 10) * 2
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('https://example.com');
        expect(result.key.subkey).to.equal("246");
    });

    it('should ignore mappings for non-existing attributes', () => {
        const mapping = {
            'url': (value) => 'https://' + value + '.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('');
    });

    it('should ignore mappings for invalid option paths', () => {
        element.setAttribute('data-monster-option-nonexistent', 'value');
        const mapping = {
            'nonexistent': (value) => value + 'bar'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result).to.deep.equal(options);
    });

    it('should apply mapping only to specified attributes', () => {
        element.setAttribute('data-monster-option-url', 'example');
        element.setAttribute('data-monster-option-key-subkey', '123');
        const mapping = {
            'url': (value) => 'https://' + value + '.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('https://example.com');
        expect(result.key.subkey).to.equal('123');
    });

    it('should not apply mapping if not a function', () => {
        element.setAttribute('data-monster-option-url', 'example');
        const mapping = {
            'url': 'https://example.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('example');
    });

    it('should apply mapping with custom prefix', () => {
        element.setAttribute('data-custom-option-url', 'example');
        const mapping = {
            'url': (value) => 'https://' + value + '.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping, 'data-custom-option-');

        expect(result.url).to.equal('https://example.com');
    });

    it('should not apply mapping with incorrect custom prefix', () => {
        element.setAttribute('data-custom-option-url', 'example');
        const mapping = {
            'url': (value) => 'https://' + value + '.com'
        };

        const result = initOptionsFromAttributes(element, options, mapping);

        expect(result.url).to.equal('');
    });

    it('should apply case sensitive mapping', () => {
        element.setAttribute('data-monster-option-key-caseSensitive', 'false');
        const result = initOptionsFromAttributes(element, options);

        expect(result.key.caseSensitive).to.equal(false);
    });

    it('should support kebab-case aliases for camelCase option names', () => {
        options = {
            popper: {
                contentOverflow: 'both',
            },
            message: {
                width: {
                    viewportRatio: 0.7,
                },
            },
        };

        element.setAttribute('data-monster-option-popper-content-overflow', 'horizontal');
        element.setAttribute('data-monster-option-message-width-viewport-ratio', '0.9');

        const result = initOptionsFromAttributes(element, options);

        expect(result.popper.contentOverflow).to.equal('horizontal');
        expect(result.message.width.viewportRatio).to.equal(0.9);
    });

    it('should preserve visible for popper content overflow attributes', () => {
        options = {
            popper: {
                contentOverflow: 'both',
            },
        };

        element.setAttribute('data-monster-option-popper-content-overflow', 'visible');

        const result = initOptionsFromAttributes(element, options);

        expect(result.popper.contentOverflow).to.equal('visible');
    });

});
