import { beforeEach, describe, expect, it, vi } from 'vitest';
import { DynamicListReducer } from './DynamicListReducer';
import { addItem, removeItem } from './DynamicListReducer.actions';
import { DynamicListReducerInit } from './DynamicListReducer.init';
import {
  DynamicListReducerActionType,
  DynamicListReducerState,
} from './DynamicListReducer.types';

vi.mock('./DynamicListReducer.init');
vi.mock('./DynamicListReducer.actions', () => ({
  addItem: vi.fn(),
  removeItem: vi.fn().mockReturnValue([]),
}));

interface Data {
  position?: number;
  id: number;
}

const dataSet: Data[] = [
  { position: 1, id: 1 },
  { position: 2, id: 2 },
  { position: 5, id: 5 },
  { position: 6, id: 6 },
  { position: 7, id: 7 },
  { position: 8, id: 8 },
  { position: 20, id: 20 },
  { position: 100, id: 100 },
];

const initialState: DynamicListReducerState<Data> = {
  items: dataSet,
  nextPosition: 1,
  canAddItems: false,
  positionPropertyName: 'position',
  maxItemLimit: 10,
  allowNewData: true,
};

describe('Dynamic List Reducer', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('calls addItem and DynamicListReducerInit when action is add', () => {
    DynamicListReducer(initialState, {
      type: DynamicListReducerActionType.Add,
      item: { id: 10, position: 10 },
    });

    expect(addItem).toHaveBeenCalledTimes(1);
    expect(addItem).toHaveBeenCalledWith(
      { id: 10, position: 10 },
      dataSet,
      'position',
    );
    expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
  });

  it('calls removeItem and DynamicListReducerInit when action is remove', () => {
    DynamicListReducer(initialState, {
      type: DynamicListReducerActionType.Remove,
      item: { id: 10, position: 10 },
    });

    expect(removeItem).toHaveBeenCalledTimes(1);
    expect(removeItem).toHaveBeenCalledWith(
      { id: 10, position: 10 },
      dataSet,
      'position',
    );
    expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
  });

  it('calls removeItem, addItem and DynamicListReducerInit when action is update', () => {
    DynamicListReducer(initialState, {
      type: DynamicListReducerActionType.Update,
      currentItem: { position: 20, id: 20 },
      newItem: { id: 10, position: 11 },
    });

    expect(removeItem).toHaveBeenCalledTimes(1);
    expect(removeItem).toHaveBeenCalledWith(
      { position: 20, id: 20 },
      dataSet,
      'position',
    );
    expect(addItem).toHaveBeenCalledTimes(1);
    expect(addItem).toHaveBeenCalledWith(
      { id: 10, position: 11 },
      [],
      'position',
    );
    expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
  });

  it('calls DynamicListReducerInit with new items when action is reset', () => {
    DynamicListReducer(initialState, {
      type: DynamicListReducerActionType.Reset,
      items: dataSet,
      positionPropertyName: 'id',
      maxItemLimit: 5,
      allowNewData: false,
    });

    expect(DynamicListReducerInit).toHaveBeenCalledTimes(1);
    expect(DynamicListReducerInit).toHaveBeenCalledWith({
      initialValue: dataSet,
      positionPropertyName: 'id',
      maxItemLimit: 5,
      allowNewData: false,
    });
  });
});
