import {
    resolveCondition,
    computeThemeData,
    toPixel,
    lineHeight,
    parseChartLanguage
} from './shared.mjs';
import '../tests/helpers/setup-browser-env.mjs';
import test from 'ava';
import set from 'lodash/set.js';

test('resolveCondition - all', t => {
    t.is(resolveCondition(['all', true, true, false]), false);
    t.is(resolveCondition(['all', true, true, true]), true);
    t.is(resolveCondition(['all', true, true]), true);
});

test('resolveCondition - any', t => {
    t.is(resolveCondition(['any', true, true, false]), true);
    t.is(resolveCondition(['any', true, true, true]), true);
    t.is(resolveCondition(['any', false, false]), false);
});

test('resolveCondition - not', t => {
    t.is(resolveCondition(['!', true]), false);
    t.is(resolveCondition(['!', false]), true);
});

test('resolveCondition - in', t => {
    t.is(resolveCondition(['in', 'x', ['x', 'y', 'z']]), true);
    t.is(resolveCondition(['in', 'a', ['x', 'y', 'z']]), false);
});

test('resolveCondition - less, equal, more', t => {
    t.is(resolveCondition(['==', 42, 42]), true);
    t.is(resolveCondition(['==', 42, 41]), false);
    t.is(resolveCondition(['!=', 42, 42]), false);
    t.is(resolveCondition(['!=', 42, 41]), true);
    t.is(resolveCondition(['>', 1, 2]), false);
    t.is(resolveCondition(['>', 2, 2]), false);
    t.is(resolveCondition(['>', 3, 2]), true);
    t.is(resolveCondition(['>=', 1, 2]), false);
    t.is(resolveCondition(['>=', 2, 2]), true);
    t.is(resolveCondition(['>=', 3, 2]), true);
    t.is(resolveCondition(['<', 1, 2]), true);
    t.is(resolveCondition(['<', 2, 2]), false);
    t.is(resolveCondition(['<', 3, 2]), false);
    t.is(resolveCondition(['<=', 1, 2]), true);
    t.is(resolveCondition(['<=', 2, 2]), true);
    t.is(resolveCondition(['<=', 3, 2]), false);
});

test('resolveCondition - get', t => {
    t.is(resolveCondition(['get', 'width'], { width: 420 }), 420);
    t.is(resolveCondition(['get', 'type'], { type: 'd3-lines' }), 'd3-lines');
    t.is(resolveCondition(['get', 'custom.foo'], { custom: { foo: 42 } }), 42);
});

test('resolveCondition - has', t => {
    t.is(resolveCondition(['has', 'width'], { width: 420 }), true);
    t.is(resolveCondition(['has', 'type'], { type: 'd3-lines' }), true);
    t.is(resolveCondition(['has', 'headline'], { headline: 'Foo' }), true);
    t.is(resolveCondition(['has', 'headline'], { headline: '' }), false);
    t.is(resolveCondition(['has', 'title'], { headline: '' }), false);
});

test('resolveCondition - length', t => {
    t.is(resolveCondition(['length', 'title'], { title: 'This is the title' }), 5);
    t.is(resolveCondition(['length', ['get', 'title']], { title: 'This is the title' }), 17);
});

test('resolveCondition - stripHtml', t => {
    t.is(resolveCondition(['stripHtml', '<b>foo</b> &gt; bar']), 'foo &gt; bar');
    t.is(
        resolveCondition(['stripHtml', ['get', 'title']], { title: '<b>foo</b> &gt; bar' }),
        'foo &gt; bar'
    );
});

test('resolveCondition - combined', t => {
    t.is(resolveCondition(['>', ['get', 'width'], 400], { width: 420 }), true);
    t.is(resolveCondition(['>', ['get', 'width'], ['get', 'foo']], { width: 420, foo: 400 }), true);
    t.is(resolveCondition(['all', ['get', 'custom.bool'], true], { custom: { bool: true } }), true);
    t.is(
        resolveCondition(
            ['all', ['>', ['get', 'width'], 400], ['==', ['get', 'type'], 'd3-lines']],
            {
                width: 450,
                type: 'd3-lines'
            }
        ),
        true
    );
    t.is(
        resolveCondition(
            [
                'any',
                ['<=', ['get', 'width'], 400],
                ['in', ['get', 'type'], ['d3-lines', 'd3-area']]
            ],
            {
                width: 450,
                type: 'd3-lines'
            }
        ),
        true
    );
});

test('computeThemeData - does not change source theme data', t => {
    const inputTheme = {
        colors: { background: 'white' },
        overrides: [
            {
                condition: true,
                settings: {
                    'colors.background': '#eeeeee'
                }
            }
        ]
    };
    const outputTheme = computeThemeData(inputTheme, {});
    t.is(outputTheme.colors.background, '#eeeeee');
    t.is(inputTheme.colors.background, 'white');
});

test('computeThemeData - multiple overrides are executed in order', t => {
    const inputTheme = {
        colors: { background: 'white' },
        overrides: [
            {
                condition: true,
                settings: {
                    'colors.background': '#eeeeee'
                }
            },
            {
                condition: true,
                settings: {
                    'colors.background': '#dddddd'
                }
            }
        ]
    };
    const outputTheme = computeThemeData(inputTheme, {});
    t.is(outputTheme.colors.background, '#dddddd');
});

test('computeThemeData - conditions are evaluated', t => {
    const inputTheme = {
        colors: { background: 'white' },
        overrides: [
            {
                condition: ['>', ['get', 'foo'], 42],
                settings: {
                    'colors.background': 'red'
                }
            }
        ]
    };
    const res1 = computeThemeData(inputTheme, { foo: 41 });
    const res2 = computeThemeData(inputTheme, { foo: 42 });
    const res3 = computeThemeData(inputTheme, { foo: 43 });
    t.is(res1.colors.background, 'white');
    t.is(res2.colors.background, 'white');
    t.is(res3.colors.background, 'red');
});

test('computeThemeData - override array ite,s', t => {
    const inputTheme = {
        colors: { palette: ['red', 'green', 'blue'] },
        overrides: [
            {
                condition: true,
                settings: {
                    'colors.palette.1': 'yellow'
                }
            }
        ]
    };
    const res = computeThemeData(inputTheme);
    t.is(res.colors.palette[0], 'red');
    t.is(res.colors.palette[1], 'yellow');
    t.is(res.colors.palette[2], 'blue');
});

test('computeThemeData - overrides may not change overrides', t => {
    const inputTheme = {
        colors: { background: 'white' },
        overrides: [
            {
                condition: true,
                settings: {
                    'overrides.0.condition': false
                }
            }
        ]
    };
    t.throws(() => computeThemeData(inputTheme));
});

test('computeThemeData - darkMode overrides', t => {
    const inputTheme = {
        colors: { background: 'white' },
        overrides: [
            {
                condition: true,
                type: 'darkMode',
                settings: {
                    'colors.background': '#222222'
                }
            }
        ]
    };
    t.is(computeThemeData(inputTheme, {}, false).colors.background, 'white');
    t.is(computeThemeData(inputTheme, {}, true).colors.background, '#222222');
});

test('computeThemeData - override grid settings', t => {
    const res = computeThemeData(
        createTheme({
            'style.body.background': '#ffffff',
            'style.chart.grid.general.gridLines.major.color': '#e2e2e2',
            'style.chart.grid.general.gridLines.major.width': 0.666667,
            'style.chart.grid.horizontal.gridLines.major.color': '#e2e2e2',
            'style.chart.grid.horizontal.gridLines.major.width': 0.666667,
            overrides: [
                {
                    condition: [
                        'in',
                        ['get', 'type'],
                        ['d3-dot-plot', 'd3-range-plot', 'd3-arrow-plot']
                    ],
                    settings: {
                        'style.chart.grid.general.gridLines.major.color': '#adadad',
                        'style.chart.grid.vertical.gridLines.major.color': '#adadad'
                    }
                }
            ]
        }),
        { type: 'd3-dot-plot' }
    );
    t.is(res.style.chart.grid.general.gridLines.major.color, '#adadad');
    t.is(res.style.chart.grid.horizontal.gridLines.major.color, '#e2e2e2');
    t.is(res.style.chart.grid.vertical.gridLines.major.color, '#adadad');
});

test('toPixel - append px only if input is number', t => {
    t.is(toPixel(12), '12px');
    t.is(toPixel('12'), '12');
    t.is(toPixel('12px'), '12px');
    t.is(toPixel('12cm'), '12cm');
});

test('lineHeight - only append px for line heights > 3', t => {
    t.is(lineHeight(1.5), '1.5');
    t.is(lineHeight(2), '2');
    t.is(lineHeight(3), '3');
    t.is(lineHeight(4), '4px');
    t.is(lineHeight(14), '14px');
});

test('parseChartLanguage - returns consistent format for language and locale', t => {
    t.deepEqual(parseChartLanguage(null), { locale: 'en-us', language: 'en' });
    t.deepEqual(parseChartLanguage(''), { locale: 'en-us', language: 'en' });
    t.deepEqual(parseChartLanguage('ar_AE'), { locale: 'ar-ae', language: 'ar' });
    t.deepEqual(parseChartLanguage('de-CH'), { locale: 'de-ch', language: 'de' });
});

function createTheme(keyvals = {}) {
    const theme = {};
    for (const [key, val] of Object.entries(keyvals)) {
        set(theme, key, val);
    }
    return theme;
}
