import { test, expect } from "@playwright/test";
import {
  resetFixtureSpec,
  setupProjectWithFixture,
  getFixturePath,
  navigateToSpecEditor,
  getEditorContent,
  setEditorContent,
  clickSaveButton,
  getByTestId,
  clickElement,
  fillInput,
  waitForNetworkIdle,
  waitForElement,
} from "./utils";

test.describe("Spec Editor Persistence", () => {
  test.beforeEach(async () => {
    // Reset the fixture spec file to original content before each test
    resetFixtureSpec();
  });

  test.afterEach(async () => {
    // Clean up - reset the spec file after each test
    resetFixtureSpec();
  });

  test("should open project, edit spec, save, and persist changes after refresh", async ({
    page,
  }) => {
    // Use the resolved fixture path
    const fixturePath = getFixturePath();

    // Step 1: Set up the project in localStorage pointing to our fixture
    await setupProjectWithFixture(page, fixturePath);

    // Step 2: Navigate to the app
    await page.goto("/");
    await waitForNetworkIdle(page);

    // Step 3: Verify we're on the dashboard with the project loaded
    // The sidebar should show the project selector
    const sidebar = await getByTestId(page, "sidebar");
    await sidebar.waitFor({ state: "visible", timeout: 10000 });

    // Step 4: Click on the Spec Editor in the sidebar
    await navigateToSpecEditor(page);

    // Step 5: Wait for the spec editor to load
    const specEditor = await getByTestId(page, "spec-editor");
    await specEditor.waitFor({ state: "visible", timeout: 10000 });

    // Step 6: Wait for CodeMirror to initialize (it has a .cm-content element)
    await specEditor.locator(".cm-content").waitFor({ state: "visible", timeout: 10000 });

    // Small delay to ensure editor is fully initialized
    await page.waitForTimeout(500);

    // Step 7: Modify the editor content to "hello world"
    await setEditorContent(page, "hello world");

    // Step 8: Click the save button
    await clickSaveButton(page);

    // Step 9: Refresh the page
    await page.reload();
    await waitForNetworkIdle(page);

    // Step 10: Navigate back to the spec editor
    // After reload, we need to wait for the app to initialize
    await waitForElement(page, "sidebar", { timeout: 10000 });

    // Navigate to spec editor again
    await navigateToSpecEditor(page);

    // Wait for CodeMirror to be ready
    const specEditorAfterReload = await getByTestId(page, "spec-editor");
    await specEditorAfterReload.locator(".cm-content").waitFor({ state: "visible", timeout: 10000 });

    // Small delay to ensure editor content is loaded
    await page.waitForTimeout(500);

    // Step 11: Verify the content was persisted
    const persistedContent = await getEditorContent(page);
    expect(persistedContent.trim()).toBe("hello world");
  });

  test("should handle opening project via Open Project button and file browser", async ({
    page,
  }) => {
    // This test covers the flow of:
    // 1. Clicking Open Project button
    // 2. Using the file browser to navigate to the fixture directory
    // 3. Opening the project
    // 4. Editing the spec

    // Set up without a current project to test the open project flow
    await page.addInitScript(() => {
      const mockState = {
        state: {
          projects: [],
          currentProject: null,
          currentView: "welcome",
          theme: "dark",
          sidebarOpen: true,
          apiKeys: { anthropic: "", google: "" },
          chatSessions: [],
          chatHistoryOpen: false,
          maxConcurrency: 3,
        },
        version: 0,
      };
      localStorage.setItem("automaker-storage", JSON.stringify(mockState));

      // Mark setup as complete
      const setupState = {
        state: {
          isFirstRun: false,
          setupComplete: true,
          currentStep: "complete",
          skipClaudeSetup: false,
        },
        version: 0,
      };
      localStorage.setItem("automaker-setup", JSON.stringify(setupState));
    });

    // Navigate to the app
    await page.goto("/");
    await waitForNetworkIdle(page);

    // Wait for the sidebar to be visible
    const sidebar = await getByTestId(page, "sidebar");
    await sidebar.waitFor({ state: "visible", timeout: 10000 });

    // Click the Open Project button
    const openProjectButton = await getByTestId(page, "open-project-button");

    // Check if the button is visible (it might not be in collapsed sidebar)
    const isButtonVisible = await openProjectButton
      .isVisible()
      .catch(() => false);

    if (isButtonVisible) {
      await clickElement(page, "open-project-button");

      // The file browser dialog should open
      // Note: In web mode, this might use the FileBrowserDialog component
      // which makes requests to the backend server at /api/fs/browse

      // Wait a bit to see if a dialog appears
      await page.waitForTimeout(1000);

      // Check if a dialog is visible
      const dialog = page.locator('[role="dialog"]');
      const dialogVisible = await dialog.isVisible().catch(() => false);

      if (dialogVisible) {
        // If file browser dialog is open, we need to navigate to the fixture path
        // This depends on the current directory structure

        // For now, let's verify the dialog appeared and close it
        // A full test would navigate through directories
        console.log("File browser dialog opened successfully");

        // Press Escape to close the dialog
        await page.keyboard.press("Escape");
      }
    }

    // For a complete e2e test with file browsing, we'd need to:
    // 1. Navigate through the directory tree
    // 2. Select the projectA directory
    // 3. Click "Select Current Folder"

    // Since this involves actual file system navigation,
    // and depends on the backend server being properly configured,
    // we'll verify the basic UI elements are present

    expect(sidebar).toBeTruthy();
  });
});

test.describe("Spec Editor - Full Open Project Flow", () => {
  test.beforeEach(async () => {
    // Reset the fixture spec file to original content before each test
    resetFixtureSpec();
  });

  test.afterEach(async () => {
    // Clean up - reset the spec file after each test
    resetFixtureSpec();
  });

  test("should open project via file browser, edit spec, and persist", async ({
    page,
  }) => {
    // Navigate to app first
    await page.goto("/");
    await waitForNetworkIdle(page);

    // Set up localStorage state (without a current project, but mark setup complete)
    // Using evaluate instead of addInitScript so it only runs once
    // Note: In CI, setup wizard is also skipped via NEXT_PUBLIC_SKIP_SETUP env var
    await page.evaluate(() => {
      const mockState = {
        state: {
          projects: [],
          currentProject: null,
          currentView: "welcome",
          theme: "dark",
          sidebarOpen: true,
          apiKeys: { anthropic: "", google: "" },
          chatSessions: [],
          chatHistoryOpen: false,
          maxConcurrency: 3,
        },
        version: 0,
      };
      localStorage.setItem("automaker-storage", JSON.stringify(mockState));

      // Mark setup as complete (fallback for when NEXT_PUBLIC_SKIP_SETUP isn't set)
      const setupState = {
        state: {
          isFirstRun: false,
          setupComplete: true,
          currentStep: "complete",
          skipClaudeSetup: false,
        },
        version: 0,
      };
      localStorage.setItem("automaker-setup", JSON.stringify(setupState));
    });

    // Reload to apply the localStorage state
    await page.reload();
    await waitForNetworkIdle(page);

    // Wait for sidebar
    await waitForElement(page, "sidebar", { timeout: 10000 });

    // Click the Open Project button
    const openProjectButton = await getByTestId(page, "open-project-button");
    await openProjectButton.waitFor({ state: "visible", timeout: 10000 });
    await clickElement(page, "open-project-button");

    // Wait for the file browser dialog to open
    const dialogTitle = page.locator('text="Select Project Directory"');
    await dialogTitle.waitFor({ state: "visible", timeout: 10000 });

    // Wait for the dialog to fully load (loading to complete)
    await page.waitForFunction(
      () => !document.body.textContent?.includes("Loading directories..."),
      { timeout: 10000 }
    );

    // Use the path input to directly navigate to the fixture directory
    const pathInput = await getByTestId(page, "path-input");
    await pathInput.waitFor({ state: "visible", timeout: 5000 });

    // Clear the input and type the full path to the fixture
    await fillInput(page, "path-input", getFixturePath());

    // Click the Go button to navigate to the path
    await clickElement(page, "go-to-path-button");

    // Wait for loading to complete
    await page.waitForFunction(
      () => !document.body.textContent?.includes("Loading directories..."),
      { timeout: 10000 }
    );

    // Verify we're in the right directory by checking the path display
    const pathDisplay = page.locator(".font-mono.text-sm.truncate");
    await expect(pathDisplay).toContainText("projectA");

    // Click "Select Current Folder" button
    const selectFolderButton = page.locator(
      'button:has-text("Select Current Folder")'
    );
    await selectFolderButton.click();

    // Wait for dialog to close and project to load
    await page.waitForFunction(
      () => !document.querySelector('[role="dialog"]'),
      { timeout: 10000 }
    );
    await page.waitForTimeout(500);

    // Navigate to spec editor
    const specNav = await getByTestId(page, "nav-spec");
    await specNav.waitFor({ state: "visible", timeout: 10000 });
    await clickElement(page, "nav-spec");

    // Wait for spec view with the editor (not the empty state)
    await waitForElement(page, "spec-view", { timeout: 10000 });
    const specEditorForOpenFlow = await getByTestId(page, "spec-editor");
    await specEditorForOpenFlow.locator(".cm-content").waitFor({ state: "visible", timeout: 10000 });
    await page.waitForTimeout(500);

    // Edit the content
    await setEditorContent(page, "hello world");

    // Click save button
    await clickSaveButton(page);

    // Refresh and verify persistence
    await page.reload();
    await waitForNetworkIdle(page);

    // Navigate back to spec editor
    await specNav.waitFor({ state: "visible", timeout: 10000 });
    await clickElement(page, "nav-spec");

    const specEditorAfterRefresh = await getByTestId(page, "spec-editor");
    await specEditorAfterRefresh.locator(".cm-content").waitFor({ state: "visible", timeout: 10000 });
    await page.waitForTimeout(500);

    // Verify the content persisted
    const persistedContent = await getEditorContent(page);
    expect(persistedContent.trim()).toBe("hello world");
  });
});
