import { expect, test } from "@playwright/test";
import { setupCORSBypass } from "../CORSBypass";
import { CommandBarButton, DataExplorer, Editor, QueryTab, TestAccount } from "../fx";
import { serializeMongoToJson } from "../testData";

const databaseId = "test-e2etests-mongo-pagination";
const collectionId = "test-coll-mongo-pagination";
let explorer: DataExplorer = null!;

test.setTimeout(5 * 60 * 1000);

test.describe("Test Mongo Pagination", () => {
  let queryTab: QueryTab;
  let queryEditor: Editor;

  test.beforeEach("Open query tab", async ({ page }) => {
    await setupCORSBypass(page);
    explorer = await DataExplorer.open(page, TestAccount.MongoReadonly);

    const containerNode = await explorer.waitForContainerNode(databaseId, collectionId);
    await containerNode.expand();

    const containerMenuNode = await explorer.waitForContainerDocumentsNode(databaseId, collectionId);
    await containerMenuNode.openContextMenu();
    await containerMenuNode.contextMenuItem("New Query").click();

    queryTab = explorer.queryTab("tab0");
    queryEditor = queryTab.editor();
    await queryEditor.locator.waitFor({ timeout: 30 * 1000 });
    await queryTab.executeCTA.waitFor();
    await explorer.frame.getByTestId("NotificationConsole/ExpandCollapseButton").click();
    await explorer.frame.getByTestId("NotificationConsole/Contents").waitFor();
  });

  test("should execute a query and load more results", async ({ page }) => {
    const query = "{}";

    await queryEditor.locator.click();
    await queryEditor.setText(query);

    const executeQueryButton = explorer.commandBarButton(CommandBarButton.ExecuteQuery);
    await executeQueryButton.click();

    // Wait for query execution to complete
    await expect(queryTab.resultsView).toBeVisible({ timeout: 60000 });
    await expect(queryTab.resultsEditor.locator).toBeAttached({ timeout: 30000 });

    // Get initial results
    const resultText = await queryTab.resultsEditor.text();

    if (!resultText || resultText.trim() === "" || resultText.trim() === "[]") {
      throw new Error("Query returned no results - the collection appears to be empty");
    }

    const resultData = serializeMongoToJson(resultText);

    if (resultData.length === 0) {
      throw new Error("Parsed results contain 0 documents - collection is empty");
    }

    if (resultData.length < 100) {
      expect(resultData.length).toBeGreaterThan(0);
      return;
    }

    expect(resultData.length).toBe(100);

    // Pagination test
    let totalPagesLoaded = 1;
    const maxLoadMoreAttempts = 10;

    for (let loadMoreAttempts = 0; loadMoreAttempts < maxLoadMoreAttempts; loadMoreAttempts++) {
      const loadMoreButton = queryTab.resultsView.getByText("Load more");

      try {
        await expect(loadMoreButton).toBeVisible({ timeout: 5000 });
      } catch {
        // Load more button not visible - pagination complete
        break;
      }

      const beforeClickText = await queryTab.resultsEditor.text();
      const beforeClickHash = Buffer.from(beforeClickText || "")
        .toString("base64")
        .substring(0, 50);

      await loadMoreButton.click();

      // Wait for content to update
      let editorContentChanged = false;
      for (let waitAttempt = 1; waitAttempt <= 3; waitAttempt++) {
        await page.waitForTimeout(2000);

        const currentEditorText = await queryTab.resultsEditor.text();
        const currentHash = Buffer.from(currentEditorText || "")
          .toString("base64")
          .substring(0, 50);

        if (currentHash !== beforeClickHash) {
          editorContentChanged = true;
          break;
        }
      }

      if (editorContentChanged) {
        totalPagesLoaded++;
      } else {
        // No content change detected, stop pagination
        break;
      }

      await page.waitForTimeout(1000);
    }

    // Final verification
    const finalIndicator = queryTab.resultsView.locator("text=/\\d+ - \\d+/");
    const finalIndicatorText = await finalIndicator.textContent();

    if (finalIndicatorText) {
      const match = finalIndicatorText.match(/(\d+) - (\d+)/);
      if (match) {
        const totalDocuments = parseInt(match[2]);
        expect(totalDocuments).toBe(405);
        expect(totalPagesLoaded).toBe(5);
      } else {
        throw new Error(`Invalid results indicator format: ${finalIndicatorText}`);
      }
    } else {
      expect(totalPagesLoaded).toBe(5);
    }
  });
});
