import { Bar } from '../../../../src';
import { DEFAULT_OPTIONS } from '../../../../src/plots/bar/constants';
import { salesByArea, subSalesByArea, timeColumnData } from '../../../data/sales';
import { createDiv } from '../../../utils/dom';

describe('bar', () => {
  it('x*y', () => {
    const bar = new Bar(createDiv(), {
      width: 300,
      height: 400,
      data: salesByArea,
      xField: 'sales',
      yField: 'area',
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    const positionFields = geometry.getAttribute('position').getFields();

    // 类型
    expect(geometry.type).toBe('interval');
    // 图形元素个数
    expect(bar.chart.geometries[0].elements.length).toBe(salesByArea.length);
    // x & y
    expect(positionFields).toHaveLength(2);
    expect(positionFields[0]).toBe('area');
    expect(positionFields[1]).toBe('sales');

    // 默认 yField 为 cat 类型
    // @ts-ignore
    expect(geometry.scales.area.type).toBe('cat');

    bar.destroy();
  });

  it('x*y*color', () => {
    const bar = new Bar(createDiv(), {
      width: 300,
      height: 400,
      data: salesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'area',
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    const colorFields = geometry.getAttribute('color').getFields();

    expect(colorFields).toHaveLength(1);
    expect(colorFields[0]).toBe('area');

    bar.destroy();
  });

  it('x*y*color with color', () => {
    const palette = ['red', 'yellow', 'green'];
    const bar = new Bar(createDiv(), {
      width: 300,
      height: 400,
      data: salesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'area',
      color: palette,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    const colorAttribute = geometry.getAttribute('color');
    const colorFields = colorAttribute.getFields();

    expect(colorFields).toHaveLength(1);
    expect(colorFields[0]).toBe('area');
    geometry.elements.forEach((element, index) => {
      const color = element.getModel().color;
      expect(color).toBe(palette[index % palette.length]);
    });

    bar.destroy();
  });

  it('grouped bar', () => {
    const bar = new Bar(createDiv('grouped bar'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isGroup: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });
    expect(geometry.getAdjust('stack')).toBeUndefined();

    bar.destroy();
  });

  it('grouped bar /w groupField', () => {
    const bar = new Bar(createDiv('grouped bar /w groupField'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isGroup: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });
    expect(geometry.getAdjust('stack')).toBeUndefined();

    bar.destroy();
  });

  it('grouped bar /w seriesField', () => {
    const bar = new Bar(createDiv('grouped bar /w seriesField'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isGroup: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });
    expect(geometry.getAdjust('stack')).toBeUndefined();

    bar.destroy();
  });

  it('stacked bar', () => {
    const bar = new Bar(createDiv('stacked bar'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isStack: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toBeUndefined();
    expect(geometry.getAdjust('stack')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });

    bar.destroy();
  });

  it('stacked bar /w stackField', () => {
    const bar = new Bar(createDiv('stacked bar /w stackField'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isStack: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toBeUndefined();
    expect(geometry.getAdjust('stack')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });

    bar.destroy();
  });

  it('stacked bar /w seriesField', () => {
    const bar = new Bar(createDiv('stacked bar /w seriesField'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isStack: true,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toBeUndefined();
    expect(geometry.getAdjust('stack')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });

    bar.destroy();
  });

  it('grouped bar barWidthRatio/marginRatio', () => {
    const bar = new Bar(createDiv('grouped bar barWidthRatio'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      isGroup: true,
      seriesField: 'series',
      barWidthRatio: 0.7,
      marginRatio: 0.3,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('dodge')).toMatchObject({
      xField: 'area',
      yField: 'sales',
      marginRatio: 0.3,
      dodgeRatio: 0.7,
    });

    bar.destroy();
  });

  it('stacked bar barWidthRatio/marginRatio', () => {
    const bar = new Bar(createDiv('stacked bar barWidthRatio'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
      seriesField: 'series',
      isStack: true,
      barWidthRatio: 0.5,
    });

    bar.render();

    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('stack')).toMatchObject({
      xField: 'area',
      yField: 'sales',
    });
    expect(geometry.theme.columnWidthRatio).toBe(0.5);

    bar.destroy();
  });

  it('default interaction', () => {
    const bar = new Bar(createDiv('default with active-region'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      xField: 'sales',
      yField: 'area',
    });

    bar.render();

    expect(bar.chart.interactions['active-region']).toBeDefined();

    bar.destroy();
  });

  it('x*y*cat', () => {
    const bar = new Bar(createDiv('x*y*cat'), {
      width: 300,
      height: 400,
      data: timeColumnData,
      isStack: true,
      xField: 'value',
      yField: 'year',
      seriesField: 'type',
    });

    bar.render();
    const geometry = bar.chart.geometries[0];
    expect(geometry.getAdjust('stack')).toMatchObject({
      xField: 'year',
      yField: 'value',
    });
    // 默认 yField 为 cat 类型
    // @ts-ignore
    expect(geometry.scales.year.type).toBe('cat');

    bar.destroy();
  });

  it('theme', () => {
    const bar = new Bar(createDiv('theme'), {
      width: 300,
      height: 400,
      data: salesByArea,
      xField: 'area',
      yField: 'sales',
      barWidthRatio: 0.1,
      theme: {
        styleSheet: {
          brandColor: '#FF6B3B',
          paletteQualitative10: [
            '#FF6B3B',
            '#626681',
            '#FFC100',
            '#9FB40F',
            '#76523B',
            '#DAD5B5',
            '#0E8E89',
            '#E19348',
            '#F383A2',
            '#247FEA',
          ],
          paletteQualitative20: [
            '#FF6B3B',
            '#626681',
            '#FFC100',
            '#9FB40F',
            '#76523B',
            '#DAD5B5',
            '#0E8E89',
            '#E19348',
            '#F383A2',
            '#247FEA',
            '#2BCB95',
            '#B1ABF4',
            '#1D42C2',
            '#1D9ED1',
            '#D64BC0',
            '#255634',
            '#8C8C47',
            '#8CDAE5',
            '#8E283B',
            '#791DC9',
          ],
        },
      },
    });

    bar.render();

    const theme = bar.chart.getTheme();
    expect(theme.defaultColor).toBe('#FF6B3B');
    expect(theme.columnWidthRatio).toBe(0.1);
  });

  function getBar(isGroup: boolean, isStack: boolean) {
    const bar = new Bar(createDiv('group'), {
      width: 300,
      height: 400,
      data: subSalesByArea,
      yField: 'area',
      xField: 'sales',
      seriesField: 'series',
      isGroup,
      isStack,
    });
    bar.render();
    return bar;
  }

  it('bar background', () => {
    const bar = getBar(false, false);
    expect(bar.options.barBackground).not.toBeDefined();
    expect(bar.chart.geometries[0].elements[0].shape.isGroup()).toBe(false);

    bar.update({ barBackground: { style: { fill: 'red' } } });
    expect(bar.options.barBackground).toBeDefined();
    expect(bar.chart.geometries[0].elements[0].shape.isGroup()).toBe(true);
    //@ts-ignore
    expect(bar.chart.geometries[0].elements[0].shape.getChildren()[0].attr('fill')).toBe('red');

    bar.destroy();
  });

  it('coordinate', () => {
    const plot = getBar(false, false);

    expect(plot.chart.getCoordinate().isReflect('y')).toBe(true);
    expect(plot.chart.getCoordinate().isTransposed).toBe(true);

    plot.destroy();
  });

  it('update annotations', () => {
    const plot = new Bar(createDiv(), {
      data: salesByArea,
      xField: 'area',
      yField: 'sales',
      annotations: [
        { type: 'line', start: ['min', 'median'], end: ['max', 'median'], id: 'ID' },
        { type: 'line', start: ['min', 'median'], end: ['max', 'median'] },
      ],
    });

    plot.render();

    expect(plot.chart.getController('annotation').getComponents().length).toBe(2);

    plot.addAnnotations([{ type: 'image', start: ['min', 'median'], end: ['max', 'median'], src: 'xx', id: 'ID' }]);

    const annotations = plot.chart.getController('annotation').getComponents();
    expect(annotations.length).toBe(2);
    expect(annotations.find((co) => co.extra.id === 'ID').component.get('type')).toBe('image');

    plot.addAnnotations([{ type: 'image', start: ['min', 'median'], end: ['max', 'median'], src: 'xx' }]);
    expect(plot.chart.getController('annotation').getComponents().length).toBe(3);

    plot.addAnnotations([{ type: 'image', start: ['min', 'median'], end: ['max', 'median'], src: 'xx', id: 'ID2' }]);
    expect(plot.chart.getController('annotation').getComponents().length).toBe(4);

    plot.removeAnnotations([{ id: 'ID' }]);
    expect(plot.chart.getController('annotation').getComponents().length).toBe(3);

    plot.removeAnnotations([{ id: '' }]);
    expect(plot.chart.getController('annotation').getComponents().length).toBe(3);

    plot.destroy();
  });

  it('defaultOptions 保持从 constants 中获取', () => {
    expect(Bar.getDefaultOptions()).toEqual(DEFAULT_OPTIONS);
  });
});
