import { DataFrame, FieldType, dateTimeFormatISO, DateTimeInput, DateTimeOptions, DataFrameType } from '@grafana/data';

import { logSeriesToLogsModel } from './logsModel';

jest.mock('@grafana/data', () => ({
  ...jest.requireActual('@grafana/data'),
  // this produces relative time, so the test-results would keep changing,
  // so we have to mock it
  dateTimeFormatTimeAgo: (p1: DateTimeInput, p2?: DateTimeOptions) =>
    `mock:dateTimeFormatTimeAgo:${dateTimeFormatISO(p1, p2)}`,
}));

describe('logSeriesToLogsModel should parse different logs-dataframe formats', () => {
  it('should parse a dataplane-formatted logs-frame)', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'severity',
            type: FieldType.string,
            config: {},
            values: ['info', 'debug', 'error'],
          },
          {
            name: 'attributes',
            type: FieldType.other,
            config: {},
            values: [
              {
                counter: '38141',
                label: 'val2',
              },
              {
                counter: '38143',
                label: 'val2',
              },
              {
                counter: '38142',
                label: 'val3',
              },
            ],
          },
          {
            name: 'timestamp',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
            nanos: [641000, 0, 0],
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id1', 'id2', 'id3'],
          },
          {
            name: 'body',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
        ],
        length: 3,
        meta: {
          type: DataFrameType.LogLines,
        },
      },
    ];

    const expected = {
      hasUniqueLabels: true,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          rowId: 'id1',
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 4,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38141',
            label: 'val2',
          },
          logLevel: 'info',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756641000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_id1',
          uniqueLabels: {
            counter: '38141',
            label: 'val2',
          },
        },
        {
          dataFrame: frames[0],
          rowId: 'id2',
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 4,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38143',
            label: 'val2',
          },
          logLevel: 'debug',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_id2',
          uniqueLabels: {
            counter: '38143',
            label: 'val2',
          },
        },
        {
          dataFrame: frames[0],
          rowId: 'id3',
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 4,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38142',
            label: 'val3',
          },
          logLevel: 'error',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_id3',
          uniqueLabels: {
            counter: '38142',
            label: 'val3',
          },
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse old Loki-style (grafana8.x) frames ( multi-frame )', () => {
    const frames: DataFrame[] = [
      {
        meta: {},
        refId: 'A',
        fields: [
          {
            name: 'ts',
            type: FieldType.time,
            config: { displayName: 'Time' },
            values: ['2023-06-07T12:18:36.839Z'],
          },
          {
            name: 'line',
            type: FieldType.string,
            config: {},
            values: ['line1'],
            labels: {
              counter: '34543',
              label: 'val3',
              level: 'info',
            },
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id1'],
          },
          {
            name: 'tsNs',
            type: FieldType.time,
            config: { displayName: 'Time ns' },
            values: ['1686140316839544212'],
          },
        ],
        length: 1,
      },
      {
        meta: {},
        refId: 'A',
        fields: [
          {
            name: 'ts',
            type: FieldType.time,
            config: { displayName: 'Time' },
            values: ['2023-06-07T12:18:34.632Z'],
          },
          {
            name: 'line',
            type: FieldType.string,
            config: {},
            values: ['line2'],
            labels: {
              counter: '34540',
              label: 'val3',
              level: 'error',
            },
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id2'],
          },
          {
            name: 'tsNs',
            type: FieldType.time,
            config: { displayName: 'Time ns' },
            values: ['1686140314632163066'],
          },
        ],
        length: 1,
      },
      {
        meta: {},
        refId: 'A',
        fields: [
          {
            name: 'ts',
            type: FieldType.time,
            config: { displayName: 'Time' },
            values: ['2023-06-07T12:18:35.565Z'],
          },
          {
            name: 'line',
            type: FieldType.string,
            config: {},
            values: ['line3'],
            labels: {
              counter: '34541',
              label: 'val3',
              level: 'error',
            },
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id3'],
          },
          {
            name: 'tsNs',
            type: FieldType.time,
            config: { displayName: 'Time ns' },
            values: ['1686140315565682856'],
          },
        ],
        length: 1,
      },
    ];

    const expected = {
      hasUniqueLabels: true,
      meta: [
        {
          kind: 2,
          label: 'Common labels',
          value: {
            label: 'val3',
          },
        },
      ],
      rows: [
        {
          dataFrame: frames[0],
          rowId: 'id1',
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '34543',
            label: 'val3',
            level: 'info',
          },
          logLevel: 'info',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686140316839,
          timeEpochNs: '1686140316839544212',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:18:36-06:00',
          timeLocal: '2023-06-07 06:18:36',
          timeUtc: '2023-06-07 12:18:36',
          uid: 'A_id1',
          uniqueLabels: {
            counter: '34543',
            level: 'info',
          },
        },
        {
          dataFrame: frames[1],
          rowId: 'id2',
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '34540',
            label: 'val3',
            level: 'error',
          },
          logLevel: 'error',
          raw: 'line2',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686140314632,
          timeEpochNs: '1686140314632163066',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:18:34-06:00',
          timeLocal: '2023-06-07 06:18:34',
          timeUtc: '2023-06-07 12:18:34',
          uid: 'A_id2',
          uniqueLabels: {
            counter: '34540',
            level: 'error',
          },
        },
        {
          dataFrame: frames[2],
          rowId: 'id3',
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '34541',
            label: 'val3',
            level: 'error',
          },
          logLevel: 'error',
          raw: 'line3',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686140315565,
          timeEpochNs: '1686140315565682856',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:18:35-06:00',
          timeLocal: '2023-06-07 06:18:35',
          timeUtc: '2023-06-07 12:18:35',
          uid: 'A_id3',
          uniqueLabels: {
            counter: '34541',
            level: 'error',
          },
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse a Loki-style frame (single-frame, labels-in-json)', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'labels',
            type: FieldType.other,
            config: {},
            values: [
              {
                counter: '38141',
                label: 'val2',
                level: 'warning',
              },
              {
                counter: '38143',
                label: 'val2',
                level: 'info',
              },
              {
                counter: '38142',
                label: 'val3',
                level: 'info',
              },
            ],
          },
          {
            name: 'Time',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
            nanos: [641000, 0, 0],
          },
          {
            name: 'Line',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
          {
            name: 'tsNs',
            type: FieldType.string,
            config: {},
            values: ['1686142519756641000', '1686142520411000000', '1686142519997000000'],
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id1', 'id2', 'id3'],
          },
        ],
        length: 3,
        meta: {
          custom: {
            frameType: 'LabeledTimeValues',
          },
        },
      },
    ];

    const expected = {
      hasUniqueLabels: true,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          rowId: 'id1',
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 2,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38141',
            label: 'val2',
            level: 'warning',
          },
          logLevel: 'warning',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756641000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_id1',
          uniqueLabels: {
            counter: '38141',
            label: 'val2',
            level: 'warning',
          },
        },
        {
          dataFrame: frames[0],
          rowId: 'id2',
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 2,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38143',
            label: 'val2',
            level: 'info',
          },
          logLevel: 'info',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_id2',
          uniqueLabels: {
            counter: '38143',
            label: 'val2',
            level: 'info',
          },
        },
        {
          dataFrame: frames[0],
          rowId: 'id3',
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 2,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {
            counter: '38142',
            label: 'val3',
            level: 'info',
          },
          logLevel: 'info',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_id3',
          uniqueLabels: {
            counter: '38142',
            label: 'val3',
            level: 'info',
          },
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse an Elasticsearch-style frame', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        meta: {},
        fields: [
          {
            name: '@timestamp',
            type: FieldType.time,
            config: {},
            values: [1686143280325, 1686143279324, 1686143278324],
          },
          {
            name: 'line',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
          {
            name: '_id',
            type: FieldType.string,
            config: {},
            values: ['id1', 'id2', 'id3'],
          },
          {
            name: '_index',
            type: FieldType.string,
            config: {},
            values: ['logs-2023.06.07', 'logs-2023.06.07', 'logs-2023.06.07'],
          },
          {
            name: '_source',
            type: FieldType.other,
            config: {},
            values: [
              {
                '@timestamp': '2023-06-07T13:08:00.325Z',
                counter: '300',
                label: 'val2',
                level: 'info',
                line: 'line1',
                shapes: [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
              },
              {
                '@timestamp': '2023-06-07T13:07:59.324Z',
                counter: '299',
                label: 'val1',
                level: 'error',
                line: 'line2',
                shapes: [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
              },
              {
                '@timestamp': '2023-06-07T13:07:58.324Z',
                counter: '298',
                label: 'val2',
                level: 'error',
                line: 'line3',
                shapes: [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
              },
            ],
          },
          {
            name: 'counter',
            type: FieldType.string,
            config: {},
            values: ['300', '299', '298'],
          },
          {
            name: 'label',
            type: FieldType.string,
            config: {},
            values: ['val2', 'val1', 'val2'],
          },
          {
            name: 'level',
            type: FieldType.string,
            config: {},
            values: ['info', 'error', 'error'],
          },
          {
            name: 'shapes',
            type: FieldType.other,
            config: {},
            values: [
              [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
              [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
              [{ type: 'triangle' }, { type: 'triangle' }, { type: 'triangle' }, { type: 'square' }],
            ],
          },
        ],
        length: 3,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'info',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686143280325,
          timeEpochNs: '1686143280325000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T07:08:00-06:00',
          timeLocal: '2023-06-07 07:08:00',
          timeUtc: '2023-06-07 13:08:00',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'error',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686143279324,
          timeEpochNs: '1686143279324000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T07:07:59-06:00',
          timeLocal: '2023-06-07 07:07:59',
          timeUtc: '2023-06-07 13:07:59',
          uid: 'A_1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'error',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686143278324,
          timeEpochNs: '1686143278324000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T07:07:58-06:00',
          timeLocal: '2023-06-07 07:07:58',
          timeUtc: '2023-06-07 13:07:58',
          uid: 'A_2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse timestamps when no nanosecond data and no nanosecond field', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'timestamp',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
          },
          {
            name: 'body',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
        ],
        length: 3,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse timestamps when no nanosecond data and nanosecond field', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'timestamp',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
          },
          {
            name: 'body',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
          {
            name: 'tsNs',
            type: FieldType.string,
            config: {},
            values: ['1686142519756641000', '1686142520411000000', '1686142519997123456'],
          },
        ],
        length: 3,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756641000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997123456',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse timestamps when nanosecond data in the time field and no nanosecond field', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'timestamp',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
            nanos: [641, 0, 123456],
          },
          {
            name: 'body',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
        ],
        length: 3,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756000641',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997123456',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should parse timestamps when both nanosecond data and nanosecond field, the field wins', () => {
    // whether the dataframe-field wins or the nanosecond-data in the time-field wins,
    // is arbitrary at the end. we simply have to pick one option, and keep doing that.
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'timestamp',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411, 1686142519997],
            nanos: [1, 2, 3],
          },
          {
            name: 'body',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2', 'line3'],
          },
          {
            name: 'tsNs',
            type: FieldType.string,
            config: {},
            values: ['1686142519756000004', '1686142520411000005', '1686142519997000006'],
          },
        ],
        length: 3,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756000004',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000005',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line3',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line3',
          rowIndex: 2,
          searchWords: [],
          timeEpochMs: 1686142519997,
          timeEpochNs: '1686142519997000006',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should add rowId when id field exists)', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'Time',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411],
            nanos: [641000, 0],
          },
          {
            name: 'Line',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2'],
          },
          {
            name: 'id',
            type: FieldType.string,
            config: {},
            values: ['id1', 'id2'],
          },
        ],
        length: 2,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          rowId: 'id1',
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756641000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_id1',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          rowId: 'id2',
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_id2',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });

  it('should not add rowId when id field does not exist)', () => {
    const frames: DataFrame[] = [
      {
        refId: 'A',
        fields: [
          {
            name: 'Time',
            type: FieldType.time,
            config: {},
            values: [1686142519756, 1686142520411],
            nanos: [641000, 0],
          },
          {
            name: 'Line',
            type: FieldType.string,
            config: {},
            values: ['line1', 'line2'],
          },
        ],
        length: 2,
      },
    ];

    const expected = {
      hasUniqueLabels: false,
      meta: [],
      rows: [
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line1',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line1',
          rowIndex: 0,
          searchWords: [],
          timeEpochMs: 1686142519756,
          timeEpochNs: '1686142519756641000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:19-06:00',
          timeLocal: '2023-06-07 06:55:19',
          timeUtc: '2023-06-07 12:55:19',
          uid: 'A_0',
          uniqueLabels: {},
        },
        {
          dataFrame: frames[0],
          datasourceType: undefined,
          entry: 'line2',
          entryFieldIndex: 1,
          hasAnsi: false,
          hasUnescapedContent: false,
          labels: {},
          logLevel: 'unknown',
          raw: 'line2',
          rowIndex: 1,
          searchWords: [],
          timeEpochMs: 1686142520411,
          timeEpochNs: '1686142520411000000',
          timeFromNow: 'mock:dateTimeFormatTimeAgo:2023-06-07T06:55:20-06:00',
          timeLocal: '2023-06-07 06:55:20',
          timeUtc: '2023-06-07 12:55:20',
          uid: 'A_1',
          uniqueLabels: {},
        },
      ],
    };

    expect(logSeriesToLogsModel(frames)).toStrictEqual(expected);
  });
});
