import React from "react";
import {
  render,
  screen,
  fireEvent,
  waitFor,
  within,
} from "@testing-library/react";
import { MockedProvider } from "@apollo/client/testing";
import { CorpusDropdown } from "./CorpusDropdown";
import { GET_CORPUSES } from "../../../graphql/queries";
import { selectedCorpus } from "../../../graphql/cache";
import { vi } from "vitest";

// Default mocks for initial load
const initialMocks = [
  {
    request: { query: GET_CORPUSES, variables: {} },
    result: {
      data: {
        corpuses: {
          pageInfo: {
            hasNextPage: false,
            hasPreviousPage: false,
            startCursor: null,
            endCursor: null,
          },
          edges: [
            {
              node: {
                id: "1",
                slug: "corpus-1",
                icon: null,
                title: "Corpus 1",
                creator: {
                  email: "test@example.com",
                  slug: "test-user",
                },
                description: "Description 1",
                preferredEmbedder: null,
                appliedAnalyzerIds: [],
                isPublic: false,
                is_selected: false,
                is_open: false,
                myPermissions: [],
                parent: null,
                annotations: {
                  totalCount: 0,
                },
                documents: {
                  totalCount: 0,
                  edges: [],
                },
                labelSet: null,
              },
            },
            {
              node: {
                id: "2",
                slug: "corpus-2",
                icon: null,
                title: "Corpus 2",
                creator: {
                  email: "test@example.com",
                  slug: "test-user",
                },
                description: "Description 2",
                preferredEmbedder: null,
                appliedAnalyzerIds: [],
                isPublic: false,
                is_selected: false,
                is_open: false,
                myPermissions: [],
                parent: null,
                annotations: {
                  totalCount: 0,
                },
                documents: {
                  totalCount: 0,
                  edges: [],
                },
                labelSet: null,
              },
            },
          ],
        },
      },
    },
    // No delay for initial load
  },
];

// Mocks for specific search
const searchMocks = [
  {
    request: { query: GET_CORPUSES, variables: {} },
    result: {
      data: {
        corpuses: {
          pageInfo: {
            hasNextPage: false,
            hasPreviousPage: false,
            startCursor: null,
            endCursor: null,
          },
          edges: [],
        },
      },
    },
    delay: 10, // initial in search case
  },
  {
    request: { query: GET_CORPUSES, variables: { textSearch: "Corpus 1" } },
    result: {
      data: {
        corpuses: {
          pageInfo: {
            hasNextPage: false,
            hasPreviousPage: false,
            startCursor: null,
            endCursor: null,
          },
          edges: [
            {
              node: {
                id: "1",
                slug: "corpus-1",
                icon: null,
                title: "Corpus 1",
                creator: {
                  email: "test@example.com",
                  slug: "test-user",
                },
                description: "Description 1",
                preferredEmbedder: null,
                appliedAnalyzerIds: [],
                isPublic: false,
                is_selected: false,
                is_open: false,
                myPermissions: [],
                parent: null,
                annotations: {
                  totalCount: 0,
                },
                documents: {
                  totalCount: 0,
                  edges: [],
                },
                labelSet: null,
              },
            },
          ],
        },
      },
    },
    delay: 10,
  },
  // Duplicate mock for potential second query with same search term
  {
    request: { query: GET_CORPUSES, variables: { textSearch: "Corpus 1" } },
    result: {
      data: {
        corpuses: {
          pageInfo: {
            hasNextPage: false,
            hasPreviousPage: false,
            startCursor: null,
            endCursor: null,
          },
          edges: [
            {
              node: {
                id: "1",
                slug: "corpus-1",
                icon: null,
                title: "Corpus 1",
                creator: {
                  email: "test@example.com",
                  slug: "test-user",
                },
                description: "Description 1",
                preferredEmbedder: null,
                appliedAnalyzerIds: [],
                isPublic: false,
                is_selected: false,
                is_open: false,
                myPermissions: [],
                parent: null,
                annotations: {
                  totalCount: 0,
                },
                documents: {
                  totalCount: 0,
                  edges: [],
                },
                labelSet: null,
              },
            },
          ],
        },
      },
    },
    delay: 10,
  },
];

describe("CorpusDropdown", () => {
  it("renders corpus options and allows selection", async () => {
    render(
      <MockedProvider mocks={initialMocks} addTypename={false}>
        <CorpusDropdown />
      </MockedProvider>
    );

    await waitFor(() =>
      expect(
        screen.queryByText("Error loading corpuses")
      ).not.toBeInTheDocument()
    );
    const dropdownElement = await screen.findByRole("combobox");

    fireEvent.click(dropdownElement);
    const listbox = await screen.findByRole("listbox");
    expect(await within(listbox).findByText("Corpus 1")).toBeInTheDocument();
    expect(await within(listbox).findByText("Corpus 2")).toBeInTheDocument();

    fireEvent.click(within(listbox).getByText("Corpus 1"));

    await waitFor(() => {
      const selected = selectedCorpus();
      expect(selected).toBeTruthy();
      expect(selected?.id).toBe("1");
      expect(selected?.title).toBe("Corpus 1");
      expect(selected?.description).toBe("Description 1");
      expect(dropdownElement).toHaveTextContent("Corpus 1");
    });
  });

  it("fetches corpuses based on search query", async () => {
    vi.useFakeTimers({ shouldAdvanceTime: true });
    render(
      <MockedProvider mocks={searchMocks} addTypename={false}>
        <CorpusDropdown />
      </MockedProvider>
    );

    // Wait for initial load
    await vi.advanceTimersByTimeAsync(50);

    await waitFor(() => {
      expect(
        screen.queryByText("Error loading corpuses")
      ).not.toBeInTheDocument();
    });

    // Click combobox to open dropdown (search input only renders when open)
    const dropdownElement = screen.getByRole("combobox");
    expect(dropdownElement).not.toHaveAttribute("aria-disabled", "true");
    fireEvent.click(dropdownElement);

    // Find search input (os-legal/ui uses role="searchbox")
    const searchInput = await screen.findByRole("searchbox");
    expect(searchInput).not.toBeDisabled();
    fireEvent.change(searchInput, { target: { value: "Corpus 1" } });

    // Advance timers for debounce (300ms) and mock fetch
    await vi.advanceTimersByTimeAsync(400);

    await waitFor(() => {
      expect(
        screen.queryByText("Error loading corpuses")
      ).not.toBeInTheDocument();
    });

    await waitFor(() => {
      const corpus1Option = screen.queryByRole("option", {
        name: /Corpus 1/i,
      });
      expect(corpus1Option).toBeInTheDocument();
    });

    expect(
      screen.queryByRole("option", { name: /Corpus 2/i })
    ).not.toBeInTheDocument();

    vi.runOnlyPendingTimers();
    vi.useRealTimers();
  });
});
