const Declaration = require('../lib/declaration');
const Prefixes    = require('../lib/prefixes');
const Browsers    = require('../lib/browsers');
const Supports    = require('../lib/supports');
const Selector    = require('../lib/selector');
const OldValue    = require('../lib/old-value');
const Value       = require('../lib/value');
const parse       = require('postcss').parse;

const data = {
    browsers: require('caniuse-lite').agents,
    prefixes: {
        a: {
            browsers: ['firefox 21', 'firefox 20 old', 'chrome 30', 'ie 6']
        },
        b: {
            browsers: ['ie 7 new', 'firefox 20'],
            mistakes: ['-webkit-'],
            props:    ['a', '*']
        },
        c: {
            browsers: ['ie 7', 'firefox 20'],
            selector: true
        }
    }
};

const empty = new Prefixes({ }, new Browsers(data.browsers, []));
const fill  = new Prefixes(
    data.prefixes,
    new Browsers(data.browsers, ['firefox 21', 'ie 7'])
);

const cSel  = new Selector('c', ['-ms-'], fill);
const bVal  = new Value('b', ['-ms- new'], fill);
const aProp = new Declaration('a', ['-moz-'], fill);
aProp.values = [bVal];

function old(prefixed) {
    const name = prefixed.replace(/-[^-]+-( old)?/, '');
    return new OldValue(name, prefixed);
}

describe('select()', () => {

    it('selects necessary prefixes', () => {
        expect(fill.select(data.prefixes)).toEqual({
            add: {
                a: ['-moz-'],
                b: ['-ms- new'],
                c: ['-ms-']
            },
            remove: {
                a: ['-webkit-', '-ms-', '-moz- old'],
                b: ['-ms-', '-moz-', '-webkit-'],
                c: ['-moz-']
            }
        });
    });

});

describe('preprocess()', () => {

    it('preprocesses prefixes add data', () => {
        expect(fill.add).toEqual({
            'selectors': [cSel],
            'a': aProp,
            '*': {
                values: [bVal]
            },
            '@supports': new Supports(Prefixes, fill)
        });
    });

    it('preprocesses prefixes remove data', () => {
        expect(JSON.stringify(fill.remove)).toEqual(JSON.stringify({
            'selectors': [cSel.old('-moz-')],
            '-webkit-a': {
                remove: true
            },
            '-ms-a': {
                remove: true
            },
            '-moz- olda': {
                remove: true
            },
            'a': {
                values: [old('-ms-b'), old('-moz-b'), old('-webkit-b')]
            },
            '*': {
                values: [old('-ms-b'), old('-moz-b'), old('-webkit-b')]
            }
        }));
    });

});

describe('.cleaner()', () => {

    it('returns itself is no browsers are selected', () => {
        expect(empty.cleaner()).toEqual(empty);
    });

    it('returns Prefixes with empty browsers', () => {
        const cleaner = new Prefixes(data.prefixes,
            new Browsers(data.browsers, []));
        expect(Object.keys(fill.cleaner().add).length).toEqual(2);
        expect(fill.cleaner().remove).toEqual(cleaner.remove);
    });

});

describe('.decl()', () => {

    it('loads declarations by property', () => {
        expect(empty.decl('a')).toEqual(new Declaration('a'));
    });

    it('caches values', () => {
        expect(empty.decl('a')).toBe(empty.decl('a'));
    });

});

describe('.unprefixed()', () => {

    it('returns unprefixed version', () => {
        expect(empty.unprefixed('-moz-a')).toEqual('a');
    });

});

describe('.prefixed()', () => {

    it('adds prefix', () => {
        expect(empty.prefixed('a', '-ms-')).toEqual('-ms-a');
    });

    it('changes prefix', () => {
        expect(empty.prefixed('a', '-ms-')).toEqual('-ms-a');
    });

});

describe('values()', () => {

    it('returns values for this and all properties', () => {
        expect(fill.values('add', 'a')).toEqual([bVal]);
        expect(fill.values('remove', 'a')).toEqual([
            old('-ms-b'),
            old('-moz-b'),
            old('-webkit-b')
        ]);
    });

});

describe('group()', () => {

    describe('down()', () => {

        it('checks prefix group', () => {
            const css   = parse('a { -ms-a: 1; -o-a: 1; a: 1; b: 2 }');
            const props = [];

            empty.group(css.first.first).down(i => props.push(i.prop));
            expect(props).toEqual(['-o-a', 'a']);
        });

        it('checks prefix groups', () => {
            const css = parse('a { -ms-a: 1; -o-a: 1; ' +
                              'a: -o-calc(1); a: 1; a: 2 }');
            const props = [];

            empty.group(css.first.first).down(i => props.push(i.prop));
            expect(props).toEqual(['-o-a', 'a', 'a']);
        });

        it('returns check decls inside group', () => {
            const css  = parse('a { -moz-a: 1; -ms-a: 1; -o-a: 1; a: 1 }');
            const decl = css.first.first;

            expect(empty.group(decl).down(i => i.prop === '-o-a')).toBeTruthy();
            expect(empty.group(decl).down(i => i.prop === '-o-b')).toBeFalsy();
        });

    });

    describe('up()', () => {

        it('checks prefix group', () => {
            const css   = parse('a { b: 2; -ms-a: 1; -o-a: 1; a: 1 }');
            const props = [];

            empty.group(css.first.nodes[3]).up(i => props.push(i.prop));
            expect(props).toEqual(['-o-a', '-ms-a']);
        });

        it('checks prefix groups', () => {
            const css = parse('a { a: 2; -ms-a: 1; ' +
                              '-o-a: 1; a: -o-calc(1); a: 1  }');
            const props = [];

            empty.group(css.first.nodes[4]).up(i => props.push(i.prop));
            expect(props).toEqual(['a', '-o-a', '-ms-a']);
        });

        it('returns check decls inside group', () => {
            const css  = parse('a { -moz-a: 1; -ms-a: 1; -o-a: 1; a: 1 }');
            const decl = css.first.nodes[3];

            expect(empty.group(decl).up(i => i.prop === '-ms-a')).toBeTruthy();
            expect(empty.group(decl).up(i => i.prop === '-ms-b')).toBeFalsy();
        });

    });

});
