import { SINGLE_BOX_XML } from "./fixtures/diagrams"
import {
    expect,
    getChatInput,
    getIframe,
    getIframeContent,
    openSettings,
    sendMessage,
    test,
    waitForComplete,
    waitForText,
} from "./lib/fixtures"
import { createMockSSEResponse } from "./lib/helpers"

test.describe("History and Session Restore", () => {
    test("new chat button clears conversation", async ({ page }) => {
        await page.route("**/api/chat", async (route) => {
            await route.fulfill({
                status: 200,
                contentType: "text/event-stream",
                body: createMockSSEResponse(
                    SINGLE_BOX_XML,
                    "Created your test diagram.",
                ),
            })
        })

        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await test.step("create a conversation", async () => {
            await sendMessage(page, "Create a test diagram")
            await waitForText(page, "Created your test diagram.")
        })

        await test.step("click new chat button", async () => {
            const newChatButton = page.locator(
                '[data-testid="new-chat-button"]',
            )
            await expect(newChatButton).toBeVisible({ timeout: 5000 })
            await newChatButton.click()
        })

        await test.step("verify conversation is cleared", async () => {
            await expect(
                page.locator('text="Created your test diagram."'),
            ).not.toBeVisible({ timeout: 5000 })
        })
    })

    test("chat history sidebar shows past conversations", async ({ page }) => {
        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        const historyButton = page.locator(
            'button[aria-label*="History"]:not([disabled]), button:has(svg.lucide-history):not([disabled]), button:has(svg.lucide-menu):not([disabled]), button:has(svg.lucide-sidebar):not([disabled]), button:has(svg.lucide-panel-left):not([disabled])',
        )

        const buttonCount = await historyButton.count()
        if (buttonCount === 0) {
            test.skip()
            return
        }

        await historyButton.first().click()
        await expect(getChatInput(page)).toBeVisible({ timeout: 3000 })
    })

    test("conversation persists after page reload", async ({ page }) => {
        await page.route("**/api/chat", async (route) => {
            await route.fulfill({
                status: 200,
                contentType: "text/event-stream",
                body: createMockSSEResponse(
                    SINGLE_BOX_XML,
                    "This message should persist.",
                ),
            })
        })

        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await test.step("create conversation", async () => {
            await sendMessage(page, "Create persistent diagram")
            await waitForText(page, "This message should persist.")
        })

        await test.step("verify message appears before reload", async () => {
            await expect(getChatInput(page)).toBeVisible({ timeout: 10000 })
            await expect(
                page.locator('text="This message should persist."'),
            ).toBeVisible({ timeout: 10000 })
        })

        // Note: After reload, mocked responses won't persist since we're not
        // testing with real localStorage. We just verify the app loads correctly.
        await test.step("verify app loads after reload", async () => {
            await page.reload({ waitUntil: "networkidle" })
            await getIframe(page).waitFor({ state: "visible", timeout: 30000 })
            await expect(getChatInput(page)).toBeVisible({ timeout: 10000 })
        })
    })

    test("diagram state persists after reload", async ({ page }) => {
        await page.route("**/api/chat", async (route) => {
            await route.fulfill({
                status: 200,
                contentType: "text/event-stream",
                body: createMockSSEResponse(
                    SINGLE_BOX_XML,
                    "Created a diagram that should be saved.",
                ),
            })
        })

        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await sendMessage(page, "Create saveable diagram")
        await waitForComplete(page)

        await page.reload({ waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        const frame = getIframeContent(page)
        await expect(
            frame
                .locator(".geMenubarContainer, .geDiagramContainer, canvas")
                .first(),
        ).toBeVisible({ timeout: 30000 })
    })

    test("can restore from browser back/forward", async ({ page }) => {
        await page.route("**/api/chat", async (route) => {
            await route.fulfill({
                status: 200,
                contentType: "text/event-stream",
                body: createMockSSEResponse(
                    SINGLE_BOX_XML,
                    "Testing browser navigation.",
                ),
            })
        })

        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await sendMessage(page, "Test navigation")
        await waitForText(page, "Testing browser navigation.")

        await page.goto("/about", { waitUntil: "networkidle" })
        await page.goBack({ waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await expect(getChatInput(page)).toBeVisible({ timeout: 10000 })
    })

    test("settings are restored after reload", async ({ page }) => {
        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await openSettings(page)
        await page.keyboard.press("Escape")

        await page.reload({ waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await openSettings(page)
    })

    test("model selection persists", async ({ page }) => {
        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        const modelSelector = page.locator(
            'button[aria-label*="Model"], [data-testid="model-selector"], button:has-text("Claude")',
        )

        const selectorCount = await modelSelector.count()
        if (selectorCount === 0) {
            test.skip()
            return
        }

        const initialModel = await modelSelector.first().textContent()

        await page.reload({ waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        const modelAfterReload = await modelSelector.first().textContent()
        expect(modelAfterReload).toBe(initialModel)
    })

    test("handles localStorage quota exceeded gracefully", async ({ page }) => {
        await page.goto("/", { waitUntil: "networkidle" })
        await getIframe(page).waitFor({ state: "visible", timeout: 30000 })

        await page.evaluate(() => {
            try {
                const largeData = "x".repeat(5 * 1024 * 1024)
                localStorage.setItem("test-large-data", largeData)
            } catch {
                // Expected to fail on some browsers
            }
        })

        await expect(getChatInput(page)).toBeVisible({ timeout: 10000 })

        await page.evaluate(() => {
            localStorage.removeItem("test-large-data")
        })
    })
})
