import { expect } from '@playwright/test'

import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
import { mockSystemStats } from '@e2e/fixtures/data/systemStats'

const MOCK_COMFYUI_VERSION = '9.99.0-e2e-test'

test.describe('Settings dialog', { tag: '@ui' }, () => {
  test('About panel renders mocked version from server', async ({
    comfyPage
  }) => {
    const stats = {
      ...mockSystemStats,
      system: {
        ...mockSystemStats.system,
        comfyui_version: MOCK_COMFYUI_VERSION
      }
    }
    await comfyPage.page.route('**/system_stats**', async (route) => {
      await route.fulfill({ json: stats })
    })
    await comfyPage.setup()

    const dialog = comfyPage.settingDialog
    await dialog.open()
    await dialog.goToAboutPanel()

    const aboutPanel = comfyPage.page.getByTestId('about-panel')
    await expect(aboutPanel).toBeVisible()
    await expect(aboutPanel).toContainText(MOCK_COMFYUI_VERSION)
    await expect(aboutPanel).toContainText('ComfyUI_frontend')
  })

  test('Toggling a boolean setting through UI persists the value', async ({
    comfyPage
  }) => {
    const settingId = 'Comfy.Validation.Workflows'
    const initialValue = await comfyPage.settings.getSetting<boolean>(settingId)

    const dialog = comfyPage.settingDialog
    await dialog.open()

    try {
      await dialog.searchBox.fill('Validate workflows')
      const settingRow = dialog.root.locator(`[data-setting-id="${settingId}"]`)
      await expect(settingRow).toBeVisible()

      await settingRow.locator('.p-toggleswitch').click()

      await expect
        .poll(() => comfyPage.settings.getSetting<boolean>(settingId))
        .toBe(!initialValue)
    } finally {
      await comfyPage.settings.setSetting(settingId, initialValue)
    }
  })

  test('Can be closed via close button', async ({ comfyPage }) => {
    const dialog = comfyPage.settingDialog
    await dialog.open()
    await expect(dialog.root).toBeVisible()

    await dialog.close()
    await expect(dialog.root).toBeHidden()
  })

  test('Escape key closes dialog', async ({ comfyPage }) => {
    const dialog = comfyPage.settingDialog
    await dialog.open()
    await expect(dialog.root).toBeVisible()

    await comfyPage.page.keyboard.press('Escape')
    await expect(dialog.root).toBeHidden()
  })

  test('Search filters settings list', async ({ comfyPage }) => {
    const dialog = comfyPage.settingDialog
    await dialog.open()

    const settingItems = dialog.root.locator('[data-setting-id]')
    const countBeforeSearch = await settingItems.count()

    await dialog.searchBox.fill('Validate workflows')
    await expect
      .poll(() => settingItems.count())
      .toBeLessThan(countBeforeSearch)
  })

  test('Search can be cleared to restore all settings', async ({
    comfyPage
  }) => {
    const dialog = comfyPage.settingDialog
    await dialog.open()

    const settingItems = dialog.root.locator('[data-setting-id]')
    const countBeforeSearch = await settingItems.count()

    await dialog.searchBox.fill('Validate workflows')
    await expect
      .poll(() => settingItems.count())
      .toBeLessThan(countBeforeSearch)

    await dialog.searchBox.clear()
    await expect.poll(() => settingItems.count()).toBe(countBeforeSearch)
  })

  test('Category navigation changes content area', async ({ comfyPage }) => {
    const dialog = comfyPage.settingDialog
    await dialog.open()

    const firstCategory = dialog.categories.first()
    const firstCategoryName = await firstCategory.textContent()
    await firstCategory.click()
    const firstContent = await dialog.contentArea.textContent()

    // Find a different category to click
    const categoryCount = await dialog.categories.count()
    let switched = false
    for (let i = 1; i < categoryCount; i++) {
      const cat = dialog.categories.nth(i)
      const catName = await cat.textContent()
      if (catName !== firstCategoryName) {
        await cat.click()
        await expect
          .poll(() => dialog.contentArea.textContent())
          .not.toBe(firstContent)
        switched = true
        break
      }
    }
    expect(switched).toBe(true)
  })

  test('Boolean setting persists after page reload', async ({ comfyPage }) => {
    const settingId = 'Comfy.Node.MiddleClickRerouteNode'
    const initialValue = await comfyPage.settings.getSetting<boolean>(settingId)

    try {
      await comfyPage.settings.setSetting(settingId, !initialValue)

      await expect
        .poll(() => comfyPage.settings.getSetting<boolean>(settingId))
        .toBe(!initialValue)

      await comfyPage.page.reload({ waitUntil: 'domcontentloaded' })
      await comfyPage.page.waitForFunction(
        () => window.app && window.app.extensionManager
      )

      await expect
        .poll(() => comfyPage.settings.getSetting<boolean>(settingId))
        .toBe(!initialValue)

      await expect
        .poll(() =>
          comfyPage.page.evaluate(
            () => window.LiteGraph!.middle_click_slot_add_default_node
          )
        )
        .toBe(!initialValue)
    } finally {
      await comfyPage.settings.setSetting(settingId, initialValue)
    }
  })

  test('Dropdown setting can be changed and persists', async ({
    comfyPage
  }) => {
    const settingId = 'Comfy.UseNewMenu'
    const initialValue = await comfyPage.settings.getSetting<string>(settingId)

    const dialog = comfyPage.settingDialog
    await dialog.open()

    try {
      await dialog.searchBox.fill('Use new menu')
      const settingRow = dialog.root.locator(`[data-setting-id="${settingId}"]`)
      await expect(settingRow).toBeVisible()

      // Wait for the search filter to fully settle — PrimeVue re-renders
      // the entire settings list after typing, and the combobox element is
      // replaced during re-render. Wait until the filtered list stabilises
      // before interacting with the combobox.
      const settingItems = dialog.root.locator('[data-setting-id]')
      await expect
        .poll(() => settingItems.count(), { timeout: 5000 })
        .toBeLessThanOrEqual(5)

      const select = settingRow.getByRole('combobox')
      await expect(select).toBeVisible()
      await expect(select).toBeEnabled()

      // Open the dropdown via its combobox role and verify it expanded.
      // Retry because the PrimeVue Select may still re-render after the
      // filter settles, causing the first click to land on a stale element.
      await expect(async () => {
        const expanded = await select.getAttribute('aria-expanded')
        if (expanded !== 'true') await select.click()
        await expect(select).toHaveAttribute('aria-expanded', 'true')
      }).toPass({ timeout: 10_000 })

      // Pick the option that is not the current value
      const targetValue = initialValue === 'Top' ? 'Disabled' : 'Top'
      await comfyPage.page
        .getByRole('option', { name: targetValue, exact: true })
        .click()

      await expect
        .poll(() => comfyPage.settings.getSetting<string>(settingId))
        .toBe(targetValue)
    } finally {
      await comfyPage.settings.setSetting(settingId, initialValue)
    }
  })
})
