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

/**
 * Helper to open settings panel and switch to Search tab
 * @param {Page} page - Playwright page object
 */
async function openSearchTab(page) {
  await page.click('button[title="Open map settings"]')
  await page.waitForTimeout(400)
  await page.click('button[title="Search"]')
  await page.waitForTimeout(200)
}

test.describe('Location Search', () => {
  // Increase timeout for search tests as they involve network requests
  test.setTimeout(60000)

  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 waitForMapLibre(page)
    await waitForLoadingComplete(page)
    await page.waitForTimeout(1500)
  })

  test.describe('Search UI', () => {
    test('displays search input in settings panel', async ({ page }) => {
      // Open settings panel
      await openSearchTab(page)

      // Search tab should be active by default
      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      await expect(searchInput).toBeVisible()
      await expect(searchInput).toHaveAttribute('placeholder', 'Enter name of a place')
    })

    test('search results container exists', async ({ page }) => {
      await openSearchTab(page)

      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')
      await expect(resultsContainer).toBeAttached()
      await expect(resultsContainer).toHaveClass(/hidden/)
    })
  })

  test.describe('Search Functionality', () => {
    test('typing in search input triggers search', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Type a search query (3+ chars to trigger search)
      await searchInput.fill('New')

      // Wait for results container to become visible or stay hidden (with timeout)
      // Search might show results or "no results" - both are valid
      try {
        await resultsContainer.waitFor({ state: 'visible', timeout: 3000 })
        // Results appeared
        expect(await resultsContainer.isVisible()).toBe(true)
      } catch (e) {
        // Results might still be hidden if search returned nothing
        // This is acceptable behavior
        console.log('Search did not return visible results')
      }
    })

    test('short queries do not trigger search', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Type single character (should not trigger search - minimum is 3 chars)
      await searchInput.fill('N')

      // Wait a bit for any potential search to trigger
      await page.waitForTimeout(500)

      // Results should stay hidden (search not triggered for short query)
      await expect(resultsContainer).toHaveClass(/hidden/)
    })

    test('clearing search clears results', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Type search query
      await searchInput.fill('Berlin')

      // Wait for potential search results
      await page.waitForTimeout(1000)

      // Clear input
      await searchInput.clear()
      await page.waitForTimeout(300)

      // Results should be hidden after clearing
      await expect(resultsContainer).toHaveClass(/hidden/)
    })
  })

  test.describe('Search Integration', () => {
    test('search manager is initialized', async ({ page }) => {
      // Wait for controller to be fully initialized
      await page.waitForTimeout(1000)

      const hasSearchManager = await page.evaluate(() => {
        const element = document.querySelector('[data-controller*="maps--maplibre"]')
        if (!element) return false

        const app = window.Stimulus || window.Application
        if (!app) return false

        const controller = app.getControllerForElementAndIdentifier(element, 'maps--maplibre')
        return controller?.searchManager !== undefined
      })

      // Search manager should exist if search targets are present
      const hasSearchTargets = await page.locator('[data-maps--maplibre-target="searchInput"]').count()
      if (hasSearchTargets > 0) {
        expect(hasSearchManager).toBe(true)
      }
    })

    test('search input has autocomplete disabled', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      await expect(searchInput).toHaveAttribute('autocomplete', 'off')
    })
  })

  test.describe('Visit Search and Creation', () => {
    test('clicking on suggestion shows visits', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Search for a location
      await searchInput.fill('Sterndamm')
      await page.waitForTimeout(800) // Wait for debounce + API

      // Wait for suggestions to appear
      const firstSuggestion = resultsContainer.locator('.search-result-item').first()
      await expect(firstSuggestion).toBeVisible({ timeout: 5000 })

      // Click on first suggestion
      await firstSuggestion.click()
      await page.waitForTimeout(1500) // Wait for visits API call

      // Results container should show visits or "no visits found"
      const hasVisits = await resultsContainer.locator('.location-result').count()
      const hasNoVisitsMessage = await resultsContainer.locator('text=No visits found').count()

      expect(hasVisits > 0 || hasNoVisitsMessage > 0).toBe(true)
    })

    test('visits are grouped by year with expand/collapse', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Search and select location
      await searchInput.fill('Sterndamm')
      await page.waitForTimeout(800)

      const firstSuggestion = resultsContainer.locator('.search-result-item').first()
      await expect(firstSuggestion).toBeVisible({ timeout: 5000 })
      await firstSuggestion.click()
      await page.waitForTimeout(1500)

      // Check if year toggles exist
      const yearToggle = resultsContainer.locator('.year-toggle').first()
      const hasYearToggle = await yearToggle.count()

      if (hasYearToggle > 0) {
        // Year visits should be hidden initially
        const yearVisits = resultsContainer.locator('.year-visits').first()
        await expect(yearVisits).toHaveClass(/hidden/)

        // Click year toggle to expand
        await yearToggle.click()
        await page.waitForTimeout(300)

        // Year visits should now be visible
        await expect(yearVisits).not.toHaveClass(/hidden/)
      }
    })

    test('clicking on visit item opens create visit modal', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Search and select location
      await searchInput.fill('Sterndamm')
      await page.waitForTimeout(800)

      const firstSuggestion = resultsContainer.locator('.search-result-item').first()
      await expect(firstSuggestion).toBeVisible({ timeout: 5000 })
      await firstSuggestion.click()
      await page.waitForTimeout(1500)

      // Check if there are visits
      const yearToggle = resultsContainer.locator('.year-toggle').first()
      const hasVisits = await yearToggle.count()

      if (hasVisits > 0) {
        // Expand year section
        await yearToggle.click()
        await page.waitForTimeout(300)

        // Click on first visit item
        const visitItem = resultsContainer.locator('.visit-item').first()
        await visitItem.click()
        await page.waitForTimeout(500)

        // Modal should appear
        const modal = page.locator('#create-visit-modal')
        await expect(modal).toBeVisible()

        // Modal should have form fields
        await expect(modal.locator('input[name="name"]')).toBeVisible()
        await expect(modal.locator('input[name="started_at"]')).toBeVisible()
        await expect(modal.locator('input[name="ended_at"]')).toBeVisible()

        // Close modal
        await modal.locator('button:has-text("Cancel")').click()
        await page.waitForTimeout(500)
      }
    })

    test('create visit modal has prefilled data', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')
      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Search and select location
      await searchInput.fill('Sterndamm')
      await page.waitForTimeout(800)

      const firstSuggestion = resultsContainer.locator('.search-result-item').first()
      await expect(firstSuggestion).toBeVisible({ timeout: 5000 })
      await firstSuggestion.click()
      await page.waitForTimeout(1500)

      // Check if there are visits
      const yearToggle = resultsContainer.locator('.year-toggle').first()
      const hasVisits = await yearToggle.count()

      if (hasVisits > 0) {
        // Expand and click visit
        await yearToggle.click()
        await page.waitForTimeout(300)

        const visitItem = resultsContainer.locator('.visit-item').first()
        await visitItem.click()
        await page.waitForTimeout(500)

        const modal = page.locator('#create-visit-modal')
        await expect(modal).toBeVisible()

        // Name should be prefilled
        const nameInput = modal.locator('input[name="name"]')
        const nameValue = await nameInput.inputValue()
        expect(nameValue.length).toBeGreaterThan(0)

        // Start and end times should be prefilled
        const startInput = modal.locator('input[name="started_at"]')
        const startValue = await startInput.inputValue()
        expect(startValue.length).toBeGreaterThan(0)

        const endInput = modal.locator('input[name="ended_at"]')
        const endValue = await endInput.inputValue()
        expect(endValue.length).toBeGreaterThan(0)

        // Close modal
        await modal.locator('button:has-text("Cancel")').click()
        await page.waitForTimeout(500)
      }
    })

    test('results container height allows viewing multiple visits', async ({ page }) => {
      await openSearchTab(page)

      const resultsContainer = page.locator('[data-maps--maplibre-target="searchResults"]')

      // Check max-height class is set appropriately (max-h-96)
      const hasMaxHeight = await resultsContainer.evaluate(el => {
        const classes = el.className
        return classes.includes('max-h-96') || classes.includes('max-h')
      })

      expect(hasMaxHeight).toBe(true)
    })
  })

  test.describe('Accessibility', () => {
    test('search input is keyboard accessible', async ({ page }) => {
      await openSearchTab(page)

      const searchInput = page.locator('[data-maps--maplibre-target="searchInput"]')

      // Focus input with keyboard
      await searchInput.focus()
      await expect(searchInput).toBeFocused()

      // Type with keyboard
      await page.keyboard.type('Paris')
      await page.waitForTimeout(500)

      const value = await searchInput.inputValue()
      expect(value).toBe('Paris')
    })

    test('search has descriptive label', async ({ page }) => {
      await openSearchTab(page)

      const label = page.locator('label:has-text("Search for a place")')
      await expect(label).toBeVisible()
    })
  })
})
