// @flow
import { getSpacingRules, getEffectiveSpaceValue } from './spacing.css-rules';

describe('getSpacingRules', () => {
  let mockTheme;

  beforeEach(() => {
    mockTheme = {
      name: 'wealthsimple',
      spacing: {
        s1: '4px',
        s2: '8px',
        s3: '16px',
        s4: '32px',
        s5: '64px',
        s6: '128px',
        s7: '256px',
      },
      buttonBorderRadius: '3px',
      cardBorderRadius: '2px',
      colorPalette: {
        // Backgrounds
        white: '#ffffff',
        background: '#f9f8f7',

        // Greys
        'greyscale-black': '#403e3d',
        'greyscale-dark': '#73706e',
        'greyscale-medium': '#bfbdbb',
        'greyscale-light': '#e6e4e3',

        // Brand colours - primary
        'brand-primary-base': '#fab131',
        'brand-primary-base-hover': '#fab131',
        'brand-primary-fg': '#e69d00',
        'brand-primary-fg-hover': '#fab131',
        'brand-primary-bg': '#fff6e6',
        'brand-primary-bg-hover': '#fab131',

        // Brand colours - secondary
        'brand-secondary-base': '#7cb7b6',
        'brand-secondary-base-hover': '#7cb7b6',
        'brand-secondary-fg': '#377674',
        'brand-secondary-fg-hover': '#7cb7b6',
        'brand-secondary-bg': '#e5f1f1',
        'brand-secondary-bg-hover': '#7cb7b6',

        // Flash messages
        'error-fg': '#B82E14',
        'error-bg': '#ffebe6',
        'success-fg': '#377674',
        'success-bg': '#e5f1f1',
        'info-fg': '#A85A00',
        'info-bg': '#fff6e6',

        // Auxiliary colours
        'aux-1': '#568aa6',
        'aux-2': '#f4adab',
        'aux-3': '#cf3813',
        'aux-4': '#1e2c46',
      },
      fonts: {},
      typescale: {
        f0: '10pt',
        f1: '13pt',
        f2: '16pt',
        f3: '18pt',
        f4: '24pt',
        f5: '30pt',
        f6: '46pt',
        f7: '42pt',
        f8: '50pt',
      },
    };
  });

  describe('getSpacingRules - non-responsive options', () => {
    describe('padding', () => {
      it('Applies left padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl0' })).toEqual(
          'padding-left: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl1' })).toEqual(
          'padding-left: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl2' })).toEqual(
          'padding-left: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl3' })).toEqual(
          'padding-left: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl4' })).toEqual(
          'padding-left: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl5' })).toEqual(
          'padding-left: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl6' })).toEqual(
          'padding-left: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pl7' })).toEqual(
          'padding-left: 256px;',
        );
      });

      it('Applies right padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr0' })).toEqual(
          'padding-right: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr1' })).toEqual(
          'padding-right: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr2' })).toEqual(
          'padding-right: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr3' })).toEqual(
          'padding-right: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr4' })).toEqual(
          'padding-right: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr5' })).toEqual(
          'padding-right: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr6' })).toEqual(
          'padding-right: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pr7' })).toEqual(
          'padding-right: 256px;',
        );
      });

      it('Applies top padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt0' })).toEqual(
          'padding-top: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt1' })).toEqual(
          'padding-top: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt2' })).toEqual(
          'padding-top: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt3' })).toEqual(
          'padding-top: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt4' })).toEqual(
          'padding-top: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt5' })).toEqual(
          'padding-top: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt6' })).toEqual(
          'padding-top: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pt7' })).toEqual(
          'padding-top: 256px;',
        );
      });

      it('Applies bottom padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb0' })).toEqual(
          'padding-bottom: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb1' })).toEqual(
          'padding-bottom: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb2' })).toEqual(
          'padding-bottom: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb3' })).toEqual(
          'padding-bottom: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb4' })).toEqual(
          'padding-bottom: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb5' })).toEqual(
          'padding-bottom: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb6' })).toEqual(
          'padding-bottom: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pb7' })).toEqual(
          'padding-bottom: 256px;',
        );
      });

      it('Applies horizontal padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph0' })).toEqual(
          'padding-right: 0;\npadding-left: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph1' })).toEqual(
          'padding-right: 4px;\npadding-left: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph2' })).toEqual(
          'padding-right: 8px;\npadding-left: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph3' })).toEqual(
          'padding-right: 16px;\npadding-left: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph4' })).toEqual(
          'padding-right: 32px;\npadding-left: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph5' })).toEqual(
          'padding-right: 64px;\npadding-left: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph6' })).toEqual(
          'padding-right: 128px;\npadding-left: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ph7' })).toEqual(
          'padding-right: 256px;\npadding-left: 256px;',
        );
      });

      it('Applies vertical padding correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv0' })).toEqual(
          'padding-top: 0;\npadding-bottom: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv1' })).toEqual(
          'padding-top: 4px;\npadding-bottom: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv2' })).toEqual(
          'padding-top: 8px;\npadding-bottom: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv3' })).toEqual(
          'padding-top: 16px;\npadding-bottom: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv4' })).toEqual(
          'padding-top: 32px;\npadding-bottom: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv5' })).toEqual(
          'padding-top: 64px;\npadding-bottom: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv6' })).toEqual(
          'padding-top: 128px;\npadding-bottom: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'pv7' })).toEqual(
          'padding-top: 256px;\npadding-bottom: 256px;',
        );
      });
    });

    describe('margins', () => {
      it('Applies left margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml0' })).toEqual(
          'margin-left: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml1' })).toEqual(
          'margin-left: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml2' })).toEqual(
          'margin-left: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml3' })).toEqual(
          'margin-left: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml4' })).toEqual(
          'margin-left: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml5' })).toEqual(
          'margin-left: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml6' })).toEqual(
          'margin-left: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'ml7' })).toEqual(
          'margin-left: 256px;',
        );
      });

      it('Applies right margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr0' })).toEqual(
          'margin-right: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr1' })).toEqual(
          'margin-right: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr2' })).toEqual(
          'margin-right: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr3' })).toEqual(
          'margin-right: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr4' })).toEqual(
          'margin-right: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr5' })).toEqual(
          'margin-right: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr6' })).toEqual(
          'margin-right: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mr7' })).toEqual(
          'margin-right: 256px;',
        );
      });

      it('Applies top margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt0' })).toEqual(
          'margin-top: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt1' })).toEqual(
          'margin-top: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt2' })).toEqual(
          'margin-top: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt3' })).toEqual(
          'margin-top: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt4' })).toEqual(
          'margin-top: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt5' })).toEqual(
          'margin-top: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt6' })).toEqual(
          'margin-top: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mt7' })).toEqual(
          'margin-top: 256px;',
        );
      });

      it('Applies bottom margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb0' })).toEqual(
          'margin-bottom: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb1' })).toEqual(
          'margin-bottom: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb2' })).toEqual(
          'margin-bottom: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb3' })).toEqual(
          'margin-bottom: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb4' })).toEqual(
          'margin-bottom: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb5' })).toEqual(
          'margin-bottom: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb6' })).toEqual(
          'margin-bottom: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mb7' })).toEqual(
          'margin-bottom: 256px;',
        );
      });

      it('Applies horizontal margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh0' })).toEqual(
          'margin-right: 0;\nmargin-left: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh1' })).toEqual(
          'margin-right: 4px;\nmargin-left: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh2' })).toEqual(
          'margin-right: 8px;\nmargin-left: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh3' })).toEqual(
          'margin-right: 16px;\nmargin-left: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh4' })).toEqual(
          'margin-right: 32px;\nmargin-left: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh5' })).toEqual(
          'margin-right: 64px;\nmargin-left: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh6' })).toEqual(
          'margin-right: 128px;\nmargin-left: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mh7' })).toEqual(
          'margin-right: 256px;\nmargin-left: 256px;',
        );
      });

      it('Applies vertical margin correctly', () => {
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv0' })).toEqual(
          'margin-top: 0;\nmargin-bottom: 0;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv1' })).toEqual(
          'margin-top: 4px;\nmargin-bottom: 4px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv2' })).toEqual(
          'margin-top: 8px;\nmargin-bottom: 8px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv3' })).toEqual(
          'margin-top: 16px;\nmargin-bottom: 16px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv4' })).toEqual(
          'margin-top: 32px;\nmargin-bottom: 32px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv5' })).toEqual(
          'margin-top: 64px;\nmargin-bottom: 64px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv6' })).toEqual(
          'margin-top: 128px;\nmargin-bottom: 128px;',
        );
        expect(getSpacingRules({ theme: mockTheme, spacing: 'mv7' })).toEqual(
          'margin-top: 256px;\nmargin-bottom: 256px;',
        );
      });
    });
  });

  describe('getSpacingRules - responsive options', () => {
    describe('small bp', () => {
      it('sets stacking rules with a small-bp media query', () => {
        const rules = getSpacingRules({
          theme: mockTheme,
          spacing: {
            sm: ['p1', 'ml4'],
          },
        });

        expect(rules).toContain(
          '@media (max-width: 768px) {' +
            'margin-left: 32px;\n' +
            'padding-top: 4px;\n' +
            'padding-right: 4px;\n' +
            'padding-bottom: 4px;\n' +
            'padding-left: 4px;' +
            '}',
        );
      });
    });

    describe('medium bp', () => {
      it('sets stacking rules with a medium-bp media query', () => {
        const rules = getSpacingRules({
          theme: mockTheme,
          spacing: {
            md: ['p1', 'ml4'],
          },
        });

        expect(rules).toContain(
          '@media (min-width: 768px) {' +
            'margin-left: 32px;\n' +
            'padding-top: 4px;\n' +
            'padding-right: 4px;\n' +
            'padding-bottom: 4px;\n' +
            'padding-left: 4px;' +
            '}',
        );
      });
    });

    describe('large bp', () => {
      it('sets stacking rules with a large-bp media query', () => {
        const rules = getSpacingRules({
          theme: mockTheme,
          spacing: {
            lg: ['p1', 'ml4'],
          },
        });

        expect(rules).toContain(
          '@media (min-width: 1024px) {' +
            'margin-left: 32px;\n' +
            'padding-top: 4px;\n' +
            'padding-right: 4px;\n' +
            'padding-bottom: 4px;\n' +
            'padding-left: 4px;' +
            '}',
        );
      });
    });

    describe('extra large bp', () => {
      it('sets stacking rules with a extra-large-bp media query', () => {
        const rules = getSpacingRules({
          theme: mockTheme,
          spacing: {
            xl: ['p1', 'ml4'],
          },
        });

        expect(rules).toContain(
          '@media (min-width: 1280px) {' +
            'margin-left: 32px;\n' +
            'padding-top: 4px;\n' +
            'padding-right: 4px;\n' +
            'padding-bottom: 4px;\n' +
            'padding-left: 4px;' +
            '}',
        );
      });
    });

    describe('multiple bp values', () => {
      it('takes smaller bp values to follow up to larger bps', () => {
        const rules = getSpacingRules({
          theme: mockTheme,
          spacing: {
            sm: ['p1', 'ml4'],
            xl: ['p3', 'mb2'],
          },
        });

        expect(rules).toContain(
          '@media (min-width: 1024px) {' +
            'margin-left: 32px;\n' +
            'padding-top: 4px;\n' +
            'padding-right: 4px;\n' +
            'padding-bottom: 4px;\n' +
            'padding-left: 4px;' +
            '}',
        );
      });
    });
  });

  describe('getEffectiveBreakPoint', () => {
    let currentBp;
    let spacing;

    describe('when the current breakpoint is specified', () => {
      beforeEach(() => {
        currentBp = 'lg';
        spacing = {
          sm: 'p1',
          md: 'p2',
          lg: 'p3',
          xl: 'p4',
        };
      });

      it('returns the value for that breakpoint', () => {
        expect(getEffectiveSpaceValue(spacing, currentBp)).toEqual('p3');
      });
    });

    describe('when the current breakpoint is not specified', () => {
      beforeEach(() => {
        currentBp = 'lg';
        spacing = {
          sm: 'p1',
          md: 'p2',
          xl: 'p4',
        };
      });

      it('returns the value for the next highest breakpoint', () => {
        expect(getEffectiveSpaceValue(spacing, currentBp)).toEqual('p2');
      });
    });

    describe('when spacing is an empty object', () => {
      beforeEach(() => {
        currentBp = 'lg';
        spacing = {};
      });

      it('returns nothing', () => {
        expect(getEffectiveSpaceValue(spacing, currentBp)).toBeUndefined();
      });
    });
  });
});
