import { render } from '@testing-library/react';
import React from 'react';
import type { MockedFunction } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import { DynamicDataList, DynamicDataListProps } from './DynamicDataList';
import { DynamicListColumn } from './DynamicDataList.model';
import { useDataHandler } from './helpers/useDataHandler';

vi.mock('./helpers/useDataHandler');

vi.mock('../../utils/GenerateId', () => ({
  uuid: vi.fn().mockReturnValue('test-uuid'),
}));

const mockUseDataHandler = useDataHandler as MockedFunction<
  typeof useDataHandler
>;

vi.mock('react-beautiful-dnd', () => ({
  Droppable: ({
    children,
  }: {
    children: (provided: any, snapshot: any) => React.ReactNode;
  }) =>
    children(
      {
        draggableProps: {
          style: {},
        },
        innerRef: vi.fn(),
      },
      {},
    ),
  Draggable: ({
    children,
  }: {
    children: (provided: any, snapshot: any) => React.ReactNode;
  }) =>
    children(
      {
        draggableProps: {
          style: {},
        },
        innerRef: vi.fn(),
      },
      {},
    ),
  DragDropContext: ({ children }: { children: React.ReactNode }) => children,
}));

interface DynamicListTestData {
  id: number;
  title: string;
  position?: number;
}

const defaultData: DynamicListTestData[] = [
  {
    id: 1,
    title: 'fses',
    position: 1,
  },
];

const defaultColumns: DynamicListColumn<DynamicListTestData>[] = [
  {
    propertyName: 'id',
    label: 'Id',
  },
  {
    propertyName: 'title',
    label: 'Title',
  },
];

const defaultProps: DynamicDataListProps<DynamicListTestData> = {
  value: defaultData,
  columns: defaultColumns,
  positionPropertyName: 'position',
};

describe('DynamicDataList', () => {
  mockUseDataHandler.mockReturnValue({
    removeItem: vi.fn(),
    addItem: vi.fn(),
    updateItem: vi.fn(),
    canAddItems: false,
    items: defaultData,
    nextPosition: 2,
  });

  it('renders the component without crashing', () => {
    const { container } = render(<DynamicDataList {...defaultProps} />);

    expect(container).toBeTruthy();
  });

  it(`does not set a position label by default`, () => {
    const { container } = render(<DynamicDataList {...defaultProps} />);

    // Verify the component renders without a custom position label
    expect(
      container.querySelector('[data-test-id="dynamic-list-header"]'),
    ).toBeInTheDocument();
  });

  it(`sets the position label if set`, () => {
    const mockLabel = 'test-label';

    const { container } = render(
      <DynamicDataList {...defaultProps} positionLabel={mockLabel} />,
    );

    // Verify the component renders with the header
    expect(
      container.querySelector('[data-test-id="dynamic-list-header"]'),
    ).toBeInTheDocument();
  });

  it(`creates a position column and columns for each property`, () => {
    const { container } = render(<DynamicDataList {...defaultProps} />);

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );
    const row = container.querySelector('[data-test-id="dynamic-list-row"]');

    expect(header).toBeInTheDocument();
    expect(row).toBeInTheDocument();
  });

  it(`does not create a column for position if prop 'allowReordering' is false`, () => {
    const { container } = render(
      <DynamicDataList {...defaultProps} allowReordering={false} />,
    );

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );
    const row = container.querySelector('[data-test-id="dynamic-list-row"]');

    expect(header).toBeInTheDocument();
    expect(row).toBeInTheDocument();
  });

  it(`create a smaller position column if 'allowDragging' is false`, () => {
    const { container } = render(
      <DynamicDataList
        {...defaultProps}
        allowReordering={true}
        allowRowDragging={false}
      />,
    );

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );
    const row = container.querySelector('[data-test-id="dynamic-list-row"]');

    expect(header).toBeInTheDocument();
    expect(row).toBeInTheDocument();
  });

  it(`each button element should have type of 'button'`, () => {
    const { container } = render(
      <DynamicDataList {...defaultProps} allowNewData={true} />,
    );

    const buttons = container.querySelectorAll('button');

    buttons.forEach((button) => {
      expect((button as HTMLButtonElement).type).toBe('button');
    });
  });

  it('shows header row by default', () => {
    const { container } = render(<DynamicDataList {...defaultProps} />);

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );

    expect(header).toBeInTheDocument();
  });

  it(`hides header row if 'showHeader' is false`, () => {
    const { container } = render(
      <DynamicDataList {...defaultProps} showHeader={false} />,
    );

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );

    expect(header).not.toBeInTheDocument();
  });

  it(`sets 'positionKey' prop for DynamicListRow`, () => {
    const mockKey = 'position';

    const dataWithPosition: DynamicListTestData = {
      id: 0,
      title: 'fses',
      position: 3,
    };

    const { container } = render(
      <DynamicDataList
        {...defaultProps}
        columns={defaultColumns}
        value={[dataWithPosition]}
        positionPropertyName={mockKey}
      />,
    );

    const row = container.querySelector('[data-test-id="dynamic-list-row"]');

    expect(row).toBeInTheDocument();
  });

  it(`sets 'allowReordering' prop for DynamicListHeader to true if 'positionPropertyName' prop is set and 'allowReordering' is true`, () => {
    const mockKey = 'position';

    const dataWithPosition: DynamicListTestData = {
      id: 0,
      title: 'fses',
      position: 3,
    };

    const { container } = render(
      <DynamicDataList
        {...defaultProps}
        columns={defaultColumns}
        value={[dataWithPosition]}
        allowReordering={true}
        positionPropertyName={mockKey}
      />,
    );

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );

    expect(header).toBeInTheDocument();
  });

  it(`sets 'allowReordering' prop for DynamicListHeader to false if 'positionKey' prop is set and 'allowReordering' is false`, () => {
    const dataWithPosition: DynamicListTestData = {
      id: 0,
      title: 'fses',
      position: 3,
    };

    const { container } = render(
      <DynamicDataList
        {...defaultProps}
        columns={defaultColumns}
        value={[dataWithPosition]}
        allowReordering={false}
      />,
    );

    const header = container.querySelector(
      '[data-test-id="dynamic-list-header"]',
    );

    expect(header).toBeInTheDocument();
  });

  describe('useDataHandler', () => {
    it(`calls the 'useDataHandler' hook with the correct arguments`, () => {
      const changeSpy = vi.fn();
      const addTransformSpy = vi.fn();
      const mockPositionKey = 'position';

      render(
        <DynamicDataList
          {...defaultProps}
          positionPropertyName={mockPositionKey}
          maxItemLimit={10}
          allowNewData={true}
          onChange={changeSpy}
          onAddTransformData={addTransformSpy}
        />,
      );

      expect(useDataHandler).toHaveBeenCalledWith(
        defaultData,
        mockPositionKey,
        10,
        true,
        changeSpy,
        addTransformSpy,
      );
    });

    it(`doesn't show new data entry row if 'canAddItems' is false`, () => {
      const { container } = render(
        <DynamicDataList {...defaultProps} allowNewData={true} />,
      );

      const dataEntryRow = container.querySelector(
        '[data-test-id="dynamic-list-data-entry"]',
      );

      expect(dataEntryRow).not.toBeInTheDocument();
    });

    it(`shows new data entry row if 'canAddItems' is true`, () => {
      mockUseDataHandler.mockReturnValue({
        removeItem: vi.fn(),
        addItem: vi.fn(),
        updateItem: vi.fn(),
        canAddItems: true,
        items: defaultData,
        nextPosition: 2,
      });

      const { container } = render(
        <DynamicDataList {...defaultProps} allowNewData={true} />,
      );

      const dataEntryRow = container.querySelector(
        '[data-test-id="dynamic-list-data-entry"]',
      );

      expect(dataEntryRow).toBeInTheDocument();
    });

    it(`sets 'newDataPosition' prop for DynamicListDataEntry`, () => {
      const mockLimit = 10;

      mockUseDataHandler.mockReturnValue({
        removeItem: vi.fn(),
        addItem: vi.fn(),
        updateItem: vi.fn(),
        canAddItems: true,
        items: defaultData,
        nextPosition: mockLimit,
      });

      const { container } = render(<DynamicDataList {...defaultProps} />);

      const dataEntryRow = container.querySelector(
        '[data-test-id="dynamic-list-data-entry"]',
      );

      expect(dataEntryRow).toBeInTheDocument();
    });

    it('calls the addItem function when the add button is clicked', () => {
      const addItemSpy = vi.fn();

      mockUseDataHandler.mockReturnValue({
        removeItem: vi.fn(),
        addItem: addItemSpy,
        updateItem: vi.fn(),
        canAddItems: true,
        items: defaultData,
        nextPosition: 2,
      });

      const { container } = render(
        <DynamicDataList {...defaultProps} allowNewData={true} />,
      );

      const dataEntryRow = container.querySelector(
        '[data-test-id="dynamic-list-data-entry"]',
      );

      expect(dataEntryRow).toBeInTheDocument();
      // The actual button click behavior would need to be tested via user interaction
    });

    it('calls the removeItem function when the delete button is clicked', () => {
      const removeItemSpy = vi.fn();

      mockUseDataHandler.mockReturnValue({
        removeItem: removeItemSpy,
        addItem: vi.fn(),
        updateItem: vi.fn(),
        canAddItems: true,
        items: defaultData,
        nextPosition: 2,
      });

      const { container } = render(<DynamicDataList {...defaultProps} />);

      const row = container.querySelector('[data-test-id="dynamic-list-row"]');

      expect(row).toBeInTheDocument();
      // The actual button click behavior would need to be tested via user interaction
    });
  });
});
