import * as EventApi from "@/features/Events/EventApi";
import searchResultReducer, {
  searchEventsAsync,
  setHits,
  setResults,
} from "@/features/Search/SearchSlice";
import { configureStore } from "@reduxjs/toolkit";

jest.mock("@/features/Events/EventApi");

describe("SearchSlice", () => {
  let store: any;

  beforeEach(() => {
    store = configureStore({
      reducer: {
        searchResult: searchResultReducer,
      },
    });
  });

  describe("initial state", () => {
    it("should have correct initial state", () => {
      const state = store.getState().searchResult;
      expect(state).toEqual({
        results: [],
        hits: 0,
        error: null,
        loading: false,
      });
    });
  });

  describe("reducers", () => {
    it("should handle setResults", () => {
      const mockResults = [
        { uid: "1", summary: "Event 1" },
        { uid: "2", summary: "Event 2" },
      ];
      store.dispatch(setResults(mockResults as any));
      expect(store.getState().searchResult.results).toEqual(mockResults);
    });

    it("should handle setHits", () => {
      store.dispatch(setHits(42));
      expect(store.getState().searchResult.hits).toBe(42);
    });
  });

  describe("searchEventsAsync", () => {
    const mockFilters = {
      searchIn: ["user1/calendar1"],
      keywords: "meeting",
      organizers: ["user@example.com"],
      attendees: ["attendee@example.com"],
    };

    it("should handle successful search", async () => {
      const mockResponse = {
        _total_hits: 5,
        _embedded: {
          events: [
            { data: { uid: "1", summary: "Test Event" } },
            { data: { uid: "2", summary: "Another Event" } },
          ],
        },
      };

      (EventApi.searchEvent as jest.Mock).mockResolvedValue(mockResponse);

      await store.dispatch(
        searchEventsAsync({ search: "test", filters: mockFilters })
      );

      const state = store.getState().searchResult;
      expect(state.loading).toBe(false);
      expect(state.hits).toBe(5);
      expect(state.results).toEqual(mockResponse._embedded.events);
      expect(state.error).toBeNull();
    });

    it("should handle search with no results", async () => {
      const mockResponse = {
        _total_hits: 0,
        _embedded: { events: [] },
      };

      (EventApi.searchEvent as jest.Mock).mockResolvedValue(mockResponse);

      await store.dispatch(
        searchEventsAsync({ search: "nonexistent", filters: mockFilters })
      );

      const state = store.getState().searchResult;
      expect(state.hits).toBe(0);
      expect(state.results).toEqual([]);
    });

    it("should handle search error", async () => {
      const mockError = new Error("Network error");
      (EventApi.searchEvent as jest.Mock).mockRejectedValue(mockError);

      await store.dispatch(
        searchEventsAsync({ search: "test", filters: mockFilters })
      );

      const state = store.getState().searchResult;
      expect(state.loading).toBe(false);
      expect(state.error).toBeTruthy();
      expect(state.results).toEqual([]);
    });

    it("should set loading state during search", async () => {
      (EventApi.searchEvent as jest.Mock).mockImplementation(
        () => new Promise((resolve) => setTimeout(resolve, 100))
      );

      const promise = store.dispatch(
        searchEventsAsync({ search: "test", filters: mockFilters })
      );

      expect(store.getState().searchResult.loading).toBe(true);
      await promise;
    });
  });
});
