import { test, expect } from '@playwright/test'
import { closeOnboardingModal } from '../../helpers/navigation.js'
import { getLayerVisibility } from '../helpers/setup.js'

test.describe('Map Settings', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/map/v2?start_at=2025-10-15T00:00&end_at=2025-10-15T23:59')
    await closeOnboardingModal(page)
    await page.waitForTimeout(2000)
  })

  test.describe('Settings Panel', () => {
    test('opens and closes settings panel', async ({ page }) => {
      const panel = page.locator('[data-maps--maplibre-target="settingsPanel"]')

      // Verify panel exists but is not open initially
      await expect(panel).toBeVisible()
      await expect(panel).not.toHaveClass(/open/)

      // Open the panel
      const settingsButton = page.locator('button[title="Open map settings"]')
      await settingsButton.click()

      // Wait for the panel to have the open class
      await expect(panel).toHaveClass(/open/, { timeout: 3000 })

      // Close the panel
      const closeButton = page.locator('button[title="Close panel"]')
      await closeButton.click()
      await expect(panel).not.toHaveClass(/open/, { timeout: 3000 })
    })

    test('displays layer controls in settings', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)

      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const pointsToggle = page.locator('label:has-text("Points")').first().locator('input.toggle')
      const routesToggle = page.locator('label:has-text("Routes")').first().locator('input.toggle')

      await expect(pointsToggle).toBeVisible()
      await expect(routesToggle).toBeVisible()
    })

    test('has tabs for different settings sections', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)

      const searchTab = page.locator('button[data-tab="search"]')
      const layersTab = page.locator('button[data-tab="layers"]')
      const settingsTab = page.locator('button[data-tab="settings"]')

      await expect(searchTab).toBeVisible()
      await expect(layersTab).toBeVisible()
      await expect(settingsTab).toBeVisible()
    })
  })

  test.describe('Layer Toggles', () => {
    test('points layer visibility matches toggle state', async ({ page }) => {
      // Wait for points layer to exist
      await page.waitForFunction(() => {
        const element = document.querySelector('[data-controller*="maps--maplibre"]')
        const app = window.Stimulus || window.Application
        const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
        return controller?.map?.getLayer('points') !== undefined
      }, { timeout: 5000 }).catch(() => false)

      const isVisible = await getLayerVisibility(page, 'points')

      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const pointsToggle = page.locator('label:has-text("Points")').first().locator('input.toggle')
      const toggleState = await pointsToggle.isChecked()

      expect(isVisible).toBe(toggleState)
    })

    test('routes layer visibility matches toggle state', async ({ page }) => {
      // Wait for routes layer to exist
      await page.waitForFunction(() => {
        const element = document.querySelector('[data-controller*="maps--maplibre"]')
        const app = window.Stimulus || window.Application
        const controller = app?.getControllerForElementAndIdentifier(element, 'maps--maplibre')
        return controller?.map?.getLayer('routes') !== undefined
      }, { timeout: 5000 }).catch(() => false)

      const isVisible = await getLayerVisibility(page, 'routes')

      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const routesToggle = page.locator('label:has-text("Routes")').first().locator('input.toggle')
      const toggleState = await routesToggle.isChecked()

      expect(isVisible).toBe(toggleState)
    })

    test('can toggle points layer', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const pointsLabel = page.locator('label:has-text("Points")').first()
      const pointsToggle = pointsLabel.locator('input.toggle')

      const initialState = await pointsToggle.isChecked()

      await pointsLabel.click()
      await page.waitForTimeout(500)

      const newState = await pointsToggle.isChecked()
      expect(newState).toBe(!initialState)

      await pointsLabel.click()
      await page.waitForTimeout(500)

      const finalState = await pointsToggle.isChecked()
      expect(finalState).toBe(initialState)
    })

    test('can toggle routes layer', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const routesLabel = page.locator('label:has-text("Routes")').first()
      const routesToggle = routesLabel.locator('input.toggle')

      const initialState = await routesToggle.isChecked()

      await routesLabel.click()
      await page.waitForTimeout(500)

      const newState = await routesToggle.isChecked()
      expect(newState).toBe(!initialState)
    })

    test('multiple layers can be toggled simultaneously', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const pointsToggle = page.locator('label:has-text("Points")').first().locator('input.toggle')
      const routesToggle = page.locator('label:has-text("Routes")').first().locator('input.toggle')

      if (!(await pointsToggle.isChecked())) {
        await pointsToggle.check()
        await page.waitForTimeout(500)
      }
      if (!(await routesToggle.isChecked())) {
        await routesToggle.check()
        await page.waitForTimeout(500)
      }

      const pointsVisible = await getLayerVisibility(page, 'points')
      const routesVisible = await getLayerVisibility(page, 'routes')

      expect(pointsVisible).toBe(true)
      expect(routesVisible).toBe(true)
    })

    test('rapidly toggling multiple layers without page reload persists all changes', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      // Get all layer toggles
      const pointsToggle = page.locator('label:has-text("Points")').first().locator('input.toggle')
      const routesToggle = page.locator('label:has-text("Routes")').first().locator('input.toggle')
      const heatmapToggle = page.locator('label:has-text("Heatmap")').first().locator('input.toggle')

      // Record initial states
      const initialPoints = await pointsToggle.isChecked()
      const initialRoutes = await routesToggle.isChecked()
      const initialHeatmap = await heatmapToggle.isChecked()

      // Rapidly toggle all three layers without waiting between toggles
      await pointsToggle.click()
      await routesToggle.click()
      await heatmapToggle.click()

      // Wait for settings to be saved (backend saves are async)
      await page.waitForTimeout(1000)

      // Verify toggle states changed
      expect(await pointsToggle.isChecked()).toBe(!initialPoints)
      expect(await routesToggle.isChecked()).toBe(!initialRoutes)
      expect(await heatmapToggle.isChecked()).toBe(!initialHeatmap)

      // Verify settings persisted in localStorage
      const settings = await page.evaluate(() => {
        return localStorage.getItem('dawarich-maps-maplibre-settings')
      })

      if (settings) {
        const parsed = JSON.parse(settings)
        expect(parsed.pointsVisible).toBe(!initialPoints)
        expect(parsed.routesVisible).toBe(!initialRoutes)
        expect(parsed.heatmapEnabled).toBe(!initialHeatmap)

        // Verify enabledMapLayers array is also updated correctly
        if (!initialPoints) {
          expect(parsed.enabledMapLayers).toContain('Points')
        } else {
          expect(parsed.enabledMapLayers).not.toContain('Points')
        }
        if (!initialRoutes) {
          expect(parsed.enabledMapLayers).toContain('Routes')
        } else {
          expect(parsed.enabledMapLayers).not.toContain('Routes')
        }
        if (!initialHeatmap) {
          expect(parsed.enabledMapLayers).toContain('Heatmap')
        } else {
          expect(parsed.enabledMapLayers).not.toContain('Heatmap')
        }
      }

      // Toggle them back rapidly
      await pointsToggle.click()
      await routesToggle.click()
      await heatmapToggle.click()

      // Wait for settings to be saved
      await page.waitForTimeout(1000)

      // Verify all states returned to initial values
      expect(await pointsToggle.isChecked()).toBe(initialPoints)
      expect(await routesToggle.isChecked()).toBe(initialRoutes)
      expect(await heatmapToggle.isChecked()).toBe(initialHeatmap)
    })
  })

  test.describe('Settings Persistence', () => {
    test('layer toggle state persists in localStorage', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="layers"]')
      await page.waitForTimeout(300)

      const pointsToggle = page.locator('label:has-text("Points")').first().locator('input.toggle')
      const initialState = await pointsToggle.isChecked()

      // Toggle to trigger a save
      await pointsToggle.click()
      await page.waitForTimeout(500)

      // Check localStorage after a toggle action
      const settings = await page.evaluate(() => {
        return localStorage.getItem('dawarich-maps-maplibre-settings')
      })

      // Settings might be saved to backend only, not localStorage
      if (settings) {
        const parsed = JSON.parse(settings)
        // After toggling, the state should be opposite of initial
        expect(parsed.pointsVisible).toBe(!initialState)
      } else {
        // If no localStorage, verify the toggle state changed
        expect(await pointsToggle.isChecked()).toBe(!initialState)
      }
    })
  })

  test.describe('Advanced Settings', () => {
    test('displays advanced settings options', async ({ page }) => {
      await page.click('button[title="Open map settings"]')
      await page.waitForTimeout(400)
      await page.click('button[data-tab="settings"]')
      await page.waitForTimeout(300)

      const panel = page.locator('[data-tab-content="settings"]')
      await expect(panel).toBeVisible()
    })
  })
})
