import { render, type RenderResult } from '@testing-library/react';

import { type Field, FieldType, MappingType, createTheme } from '@grafana/data';

import { getTextColorForBackground } from '../../../../utils/colors';

import { PillCell } from './PillCell';

describe('PillCell', () => {
  const theme = createTheme();

  const fieldWithValues = (values: unknown[]): Field => ({
    name: 'test',
    type: FieldType.string,
    values: values,
    config: {},
    display: (value: unknown) => ({ text: String(value), color: '#FF780A', numeric: NaN }),
  });

  const ser = new XMLSerializer();

  const expectHTML = (result: RenderResult, expected: string) => {
    let actual = ser.serializeToString(result.asFragment()).replace(/xmlns=".*?" /g, '');
    expect(actual).toEqual(expected.replace(/^\s*|\n/gm, ''));
  };

  // one class for lightTextPill, darkTextPill

  describe('Color by hash (classic palette)', () => {
    it('single value', () => {
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues(['value1'])}
            rowIdx={0}
            theme={theme}
          />
        ),
        `<span style="background-color: rgb(63, 43, 91); color: rgb(247, 248, 250);">value1</span>`
      );
    });

    it('empty string', () => {
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues([''])}
            rowIdx={0}
            theme={theme}
          />
        ),
        ''
      );
    });

    it('null', () => {
      const { container } = render(
        <PillCell
          getTextColorForBackground={getTextColorForBackground}
          field={fieldWithValues([])}
          rowIdx={0}
          theme={theme}
        />
      );
      expect(container).toBeEmptyDOMElement();
    });

    it('CSV values', () => {
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues(['value1,value2,value3'])}
            rowIdx={0}
            theme={theme}
          />
        ),
        `
        <span style="background-color: rgb(63, 43, 91); color: rgb(247, 248, 250);">value1</span>
        <span style="background-color: rgb(252, 226, 222); color: rgb(32, 34, 38);">value2</span>
        <span style="background-color: rgb(81, 149, 206); color: rgb(247, 248, 250);">value3</span>
        `
      );
    });

    it('JSON array values', () => {
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues(['["value1","value2","value3"]'])}
            rowIdx={0}
            theme={theme}
          />
        ),
        `
        <span style="background-color: rgb(63, 43, 91); color: rgb(247, 248, 250);">value1</span>
        <span style="background-color: rgb(252, 226, 222); color: rgb(32, 34, 38);">value2</span>
        <span style="background-color: rgb(81, 149, 206); color: rgb(247, 248, 250);">value3</span>
        `
      );
    });

    it('FieldType.other with array', () => {
      const field = fieldWithValues([['value1', 'value2', 'value3']]);
      field.type = FieldType.other;
      expectHTML(
        render(
          <PillCell getTextColorForBackground={getTextColorForBackground} field={field} rowIdx={0} theme={theme} />
        ),
        `
        <span style="background-color: rgb(63, 43, 91); color: rgb(247, 248, 250);">value1</span>
        <span style="background-color: rgb(252, 226, 222); color: rgb(32, 34, 38);">value2</span>
        <span style="background-color: rgb(81, 149, 206); color: rgb(247, 248, 250);">value3</span>
        `
      );
    });

    it('FieldType.other with array with some null values', () => {
      const field = fieldWithValues([['value1', null, 'value2', undefined, 'value3']]);
      field.type = FieldType.other;
      expectHTML(
        render(
          <PillCell getTextColorForBackground={getTextColorForBackground} field={field} rowIdx={0} theme={theme} />
        ),
        `
        <span style="background-color: rgb(63, 43, 91); color: rgb(247, 248, 250);">value1</span>
        <span style="background-color: rgb(252, 226, 222); color: rgb(32, 34, 38);">value2</span>
        <span style="background-color: rgb(81, 149, 206); color: rgb(247, 248, 250);">value3</span>
        `
      );
    });

    it('FieldType.other with non-array', () => {
      const field = fieldWithValues([{ value1: true, value2: false, value3: 42 }]);
      field.type = FieldType.other;
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues([])}
            rowIdx={0}
            theme={theme}
          />
        ),
        ''
      );
    });

    it('non-string values', () => {
      expectHTML(
        render(
          <PillCell
            getTextColorForBackground={getTextColorForBackground}
            field={fieldWithValues(['[100,200,300]'])}
            rowIdx={0}
            theme={theme}
          />
        ),
        `
        <span style="background-color: rgb(252, 226, 222); color: rgb(32, 34, 38);">100</span>
        <span style="background-color: rgb(222, 218, 247); color: rgb(32, 34, 38);">200</span>
        <span style="background-color: rgb(249, 217, 249); color: rgb(32, 34, 38);">300</span>
        `
      );
    });

    it('custom display text', () => {
      const mockField = fieldWithValues(['value1,value2,value3']);
      const field = {
        ...mockField,
        display: (value: unknown) => ({
          text: `${value} lbs`,
          color: '#FF780A',
          numeric: 0,
        }),
      } satisfies Field;

      expectHTML(
        render(
          <PillCell getTextColorForBackground={getTextColorForBackground} field={field} rowIdx={0} theme={theme} />
        ),
        `
        <span style=\"background-color: rgb(207, 250, 255); color: rgb(32, 34, 38);\">value1 lbs</span>
        <span style=\"background-color: rgb(229, 172, 14); color: rgb(247, 248, 250);\">value2 lbs</span>
        <span style=\"background-color: rgb(63, 104, 51); color: rgb(247, 248, 250);\">value3 lbs</span>
        `
      );
    });
  });

  describe('Color by value mappings', () => {
    it('CSV values', () => {
      const mockField = fieldWithValues(['success,error,warning,unknown']);
      const field = {
        ...mockField,
        config: {
          ...mockField.config,
          mappings: [
            {
              type: MappingType.ValueToText,
              options: {
                success: { color: '#00FF00' },
                error: { color: '#FF0000' },
                warning: { color: '#FFFF00' },
              },
            },
          ],
        },
        display: (value: unknown) => ({
          text: String(value),
          color:
            value === 'success'
              ? '#00FF00'
              : value === 'error'
                ? '#FF0000'
                : value === 'warning'
                  ? '#FFFF00'
                  : '#FF780A',
          numeric: 0,
        }),
      } satisfies Field;

      expectHTML(
        render(
          <PillCell getTextColorForBackground={getTextColorForBackground} field={field} rowIdx={0} theme={theme} />
        ),
        `
        <span style="background-color: rgb(0, 255, 0); color: rgb(247, 248, 250);">success</span>
        <span style="background-color: rgb(255, 0, 0); color: rgb(247, 248, 250);">error</span>
        <span style="background-color: rgb(255, 255, 0); color: rgb(32, 34, 38);">warning</span>
        <span style="background-color: rgb(255, 120, 10); color: rgb(247, 248, 250);">unknown</span>
        `
      );
    });

    // TODO: handle null values?
  });
});
