import exp from 'constants';
import { ChartProcessor } from '../chartProcessor';
import { getChartDebugPrint } from '../chartTools';

const DS1 = [
  {
    timestamp: '2023-10-01T12:00:00Z',
    value: 42.5,
    category: 'B',
    related_id: 12,
  },
  {
    timestamp: '2023-10-02T10:05:00Z',
    value: 12,
    category: 'A',
    related_id: 13,
  },
  {
    timestamp: '2023-10-03T07:10:00Z',
    value: 57,
    category: 'A',
    related_id: 5,
  },
  {
    timestamp: '2024-08-03T07:10:00Z',
    value: 33,
    category: 'B',
    related_id: 22,
  },
];

const DS2 = [
  {
    ts1: '2023-10-01T12:00:00Z',
    ts2: '2024-10-01T12:00:00Z',
    dummy1: 1,
    dummy2: 1,
    dummy3: 1,
    dummy4: 1,
    dummy5: 1,
    dummy6: 1,
    dummy7: 1,
    dummy8: 1,
    dummy9: 1,
    dummy10: 1,
    price1: '11',
    price2: '22',
  },
  {
    ts1: '2023-10-02T10:05:00Z',
    ts2: '2024-10-02T10:05:00Z',
    price1: '12',
    price2: '23',
  },
  {
    ts1: '2023-10-03T07:10:00Z',
    ts2: '2024-10-03T07:10:00Z',
    price1: '22',
    price2: '24',
  },
  {
    ts1: '2023-11-04T12:00:00Z',
    ts2: '2024-11-04T12:00:00Z',
    price1: 1,
    price2: 2,
  },
];

const DS3 = [
  {
    timestamp: '2023-10-01T12:00:00Z',
    value: 42.5,
    bitval: true,
  },
  {
    timestamp: '2023-10-02T10:05:00Z',
    value: 12,
    bitval: false,
  },
  {
    timestamp: '2023-10-03T07:10:00Z',
    value: 57,
    bitval: null,
  },
];

const DS4 = [
  {
    object_id: 710293590,
    ObjectName: 'Journal',
    Total_Reserved_kb: '68696',
    RowsCount: '405452',
  },
  {
    object_id: 182291709,
    ObjectName: 'Employee',
    Total_Reserved_kb: '732008',
    RowsCount: '1980067',
  },
  {
    object_id: 23432525,
    ObjectName: 'User',
    Total_Reserved_kb: '325352',
    RowsCount: '2233',
  },
  {
    object_id: 4985159,
    ObjectName: 'Project',
    Total_Reserved_kb: '293523',
    RowsCount: '1122',
  },
];

describe('Chart processor', () => {
  test('Simple by day test, autodetected', () => {
    const processor = new ChartProcessor();
    processor.addRows(...DS1.slice(0, 3));
    processor.finalize();
    // console.log(getChartDebugPrint(processor.charts[0]));
    expect(processor.charts.length).toEqual(6);
    const chart1 = processor.charts.find(x => !x.definition.groupingField && x.definition.xdef.field === 'timestamp');
    expect(chart1.definition.xdef.transformFunction).toEqual('date:day');
    expect(chart1.definition.ydefs).toEqual([
      expect.objectContaining({
        field: 'value',
      }),
    ]);
    expect(chart1.bucketKeysOrdered).toEqual(['2023-10-01', '2023-10-02', '2023-10-03']);

    const chart2 = processor.charts.find(x => x.definition.groupingField && x.definition.xdef.field === 'timestamp');
    expect(chart2.definition.xdef.transformFunction).toEqual('date:day');
    expect(chart2.bucketKeysOrdered).toEqual(['2023-10-01', '2023-10-02', '2023-10-03']);
    expect(chart2.definition.groupingField).toEqual('category');

    const chart3 = processor.charts.find(x => x.definition.xdef.field === 'category');
    expect(chart3.bucketKeysOrdered).toEqual(['A', 'B']);
    expect(chart3.definition.groupingField).toBeUndefined();

    const countCharts = processor.charts.filter(
      x => x.definition.ydefs.length == 1 && x.definition.ydefs[0].field == '__count'
    );
    expect(countCharts.length).toEqual(3);
  });
  test('By month grouped, autedetected', () => {
    const processor = new ChartProcessor();
    processor.addRows(...DS1.slice(0, 4));
    processor.finalize();
    expect(processor.charts.length).toEqual(6);
    const chart = processor.charts.find(
      x =>
        !x.definition.groupingField &&
        x.definition.xdef.field === 'timestamp' &&
        !x.definition.ydefs.find(y => y.field === '__count')
    );
    expect(chart.definition.xdef.transformFunction).toEqual('date:month');
    expect(chart.bucketKeysOrdered).toEqual([
      '2023-10',
      '2023-11',
      '2023-12',
      '2024-01',
      '2024-02',
      '2024-03',
      '2024-04',
      '2024-05',
      '2024-06',
      '2024-07',
      '2024-08',
    ]);
  });
  test('Detect columns', () => {
    const processor = new ChartProcessor();
    processor.autoDetectCharts = false;
    processor.addRows(...DS1);
    processor.finalize();
    expect(processor.charts.length).toEqual(0);
    expect(processor.availableColumns).toEqual([
      expect.objectContaining({
        field: 'timestamp',
      }),
      expect.objectContaining({
        field: 'value',
      }),
      expect.objectContaining({
        field: 'category',
      }),
      expect.objectContaining({
        field: 'related_id',
      }),
    ]);
  });
  test('Explicit definition', () => {
    const processor = new ChartProcessor([
      {
        chartType: 'pie',
        xdef: {
          field: 'category',
          transformFunction: 'identity',
          sortOrder: 'natural',
        },
        ydefs: [
          {
            field: 'related_id',
            aggregateFunction: 'sum',
          },
        ],
      },
    ]);
    processor.addRows(...DS1);
    processor.finalize();
    expect(processor.charts.length).toEqual(1);
    const chart = processor.charts[0];
    expect(chart.definition.xdef.transformFunction).toEqual('identity');
    expect(chart.bucketKeysOrdered).toEqual(['B', 'A']);
    expect(chart.buckets).toEqual({
      B: { related_id: 34 },
      A: { related_id: 18 },
    });
  });

  test('Two data sets with different date columns', () => {
    const processor = new ChartProcessor();
    processor.addRows(...DS2);
    processor.finalize();
    expect(processor.charts.length).toEqual(4);
    expect(processor.charts[0].definition).toEqual(
      expect.objectContaining({
        xdef: expect.objectContaining({
          field: 'ts1',
          transformFunction: 'date:day',
        }),
        ydefs: [
          expect.objectContaining({
            field: 'price1',
            aggregateFunction: 'sum',
          }),
          expect.objectContaining({
            field: 'price2',
            aggregateFunction: 'sum',
          }),
        ],
      })
    );
    expect(processor.charts[1].definition).toEqual(
      expect.objectContaining({
        xdef: expect.objectContaining({
          field: 'ts2',
          transformFunction: 'date:day',
        }),
        ydefs: [
          expect.objectContaining({
            field: 'price1',
            aggregateFunction: 'sum',
          }),
          expect.objectContaining({
            field: 'price2',
            aggregateFunction: 'sum',
          }),
        ],
      })
    );
  });

  test('Exclude boolean fields in autodetected', () => {
    const processor = new ChartProcessor();
    processor.addRows(...DS3);
    processor.finalize();
    expect(processor.charts.length).toEqual(2);
    const chart = processor.charts.find(x => !x.definition.ydefs.find(y => y.field === '__count'));
    expect(chart.definition.xdef.transformFunction).toEqual('date:day');
    expect(chart.definition.ydefs).toEqual([
      expect.objectContaining({
        field: 'value',
      }),
    ]);
  });

  test('Added field manual from GUI', () => {
    const processor = new ChartProcessor([
      {
        chartType: 'bar',
        xdef: {
          field: 'object_id',
          transformFunction: 'identity',
        },
        ydefs: [
          {
            field: 'object_id',
            aggregateFunction: 'sum',
          },
        ],
      },
    ]);
    processor.addRows(...DS4);
    processor.finalize();
    expect(processor.charts.length).toEqual(1);
    const chart = processor.charts[0];
    expect(chart.definition.xdef.transformFunction).toEqual('identity');
    expect(chart.definition.ydefs).toEqual([
      expect.objectContaining({
        field: 'object_id',
        aggregateFunction: 'sum',
      }),
    ]);
  });

  const PieMainTestData = [
    ['natural', ['Journal', 'Employee', 'User', 'Project']],
    ['ascKeys', ['Employee', 'Journal', 'Project', 'User']],
    ['descKeys', ['User', 'Project', 'Journal', 'Employee']],
    ['ascValues', ['Project', 'User', 'Journal', 'Employee']],
    ['descValues', ['Employee', 'Journal', 'User', 'Project']],
  ];

  test.each(PieMainTestData)('Pie chart - used space for DB objects (%s)', (sortOrder, expectedOrder) => {
    const processor = new ChartProcessor([
      {
        chartType: 'bar',
        xdef: {
          field: 'ObjectName',
          transformFunction: 'identity',
          sortOrder: sortOrder as any,
        },
        ydefs: [
          {
            field: 'RowsCount',
            aggregateFunction: 'sum',
          },
        ],
      },
    ]);
    processor.addRows(...DS4);
    processor.finalize();
    expect(processor.charts.length).toEqual(1);
    const chart = processor.charts[0];
    expect(chart.bucketKeysOrdered).toEqual(expectedOrder);
    expect(chart.buckets).toEqual({
      Employee: { RowsCount: 1980067 },
      Journal: { RowsCount: 405452 },
      Project: { RowsCount: 1122 },
      User: { RowsCount: 2233 },
    });
  });

  const PieOtherTestData = [
    [
      'ratio',
      0.1,
      5,
      ['Employee', 'Journal', 'Other'],
      {
        Employee: { RowsCount: 1980067 },
        Journal: { RowsCount: 405452 },
        Other: { RowsCount: 3355 },
      },
    ],
    [
      'count',
      0,
      1,
      ['Employee', 'Other'],
      {
        Employee: { RowsCount: 1980067 },
        Other: { RowsCount: 408807 },
      },
    ],
  ];

  test.each(PieOtherTestData)(
    'Pie limit test - %s',
    (_description, pieRatioLimit, pieCountLimit, expectedOrder, expectedBuckets) => {
      const processor = new ChartProcessor([
        {
          chartType: 'pie',
          pieRatioLimit: pieRatioLimit as number,
          pieCountLimit: pieCountLimit as number,
          xdef: {
            field: 'ObjectName',
            transformFunction: 'identity',
          },
          ydefs: [
            {
              field: 'RowsCount',
              aggregateFunction: 'sum',
            },
          ],
        },
      ]);
      processor.addRows(...DS4);
      processor.finalize();
      expect(processor.charts.length).toEqual(1);
      const chart = processor.charts[0];
      expect(chart.bucketKeysOrdered).toEqual(expectedOrder);
      expect(chart.buckets).toEqual(expectedBuckets);
    }
  );

  test('Incorrect chart definition', () => {
    const processor = new ChartProcessor([
      {
        chartType: 'bar',
        xdef: {
          field: 'category',
          transformFunction: 'date:day',
        },
        ydefs: [],
      },
    ]);
    processor.addRows(...DS1.slice(0, 3));
    processor.finalize();

    expect(processor.charts.length).toEqual(1);
    const chart = processor.charts[0];
    expect(chart.definition.xdef.transformFunction).toEqual('date:day');

    // console.log(getChartDebugPrint(processor.charts[0]));

    // expect(chart.definition.xdef.transformFunction).toEqual('date:day');
    // expect(chart.definition.ydefs).toEqual([
    //   expect.objectContaining({
    //     field: 'value',
    //   }),
    // ]);
    // expect(chart.bucketKeysOrdered).toEqual(['2023-10-01', '2023-10-02', '2023-10-03']);
  });
});
