import { test, expect } from '@playwright/test';
import { navigateToMap, closeOnboardingModal } from '../helpers/navigation.js';
import { waitForMap, enableLayer } from '../helpers/map.js';

test.describe('Map Layers', () => {
  test.beforeEach(async ({ page }) => {
    await navigateToMap(page);
  });

  test('should enable Routes layer and display routes', async ({ page }) => {
    // Wait for map to be ready
    await page.waitForFunction(() => {
      const container = document.querySelector('#map [data-maps-target="container"]');
      return container && container._leaflet_id !== undefined;
    }, { timeout: 10000 });

    // Navigate to date with data
    const toggleButton = page.locator('button[data-action*="map-controls#toggle"]');
    const isPanelVisible = await page.locator('[data-map-controls-target="panel"]').isVisible();

    if (!isPanelVisible) {
      await toggleButton.click();
      await page.waitForTimeout(300);
    }

    const startInput = page.locator('input[type="datetime-local"][name="start_at"]');
    await startInput.clear();
    await startInput.fill('2024-10-15T00:00');

    const endInput = page.locator('input[type="datetime-local"][name="end_at"]');
    await endInput.clear();
    await endInput.fill('2024-10-15T23:59');
    await page.click('input[type="submit"][value="Search"]');
    await page.waitForLoadState('networkidle');
    await page.waitForTimeout(1000);

    // Close onboarding modal if present
    await closeOnboardingModal(page);

    // Open layer control and enable Routes
    await page.locator('.leaflet-control-layers').hover();
    await page.waitForTimeout(300);

    const routesCheckbox = page.locator('.leaflet-control-layers-overlays label:has-text("Routes") input[type="checkbox"]');
    const isChecked = await routesCheckbox.isChecked();

    if (!isChecked) {
      await routesCheckbox.check();
      await page.waitForTimeout(1000);
    }

    // Verify routes are visible
    const hasRoutes = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      if (controller?.polylinesLayer && controller.polylinesLayer._layers) {
        return Object.keys(controller.polylinesLayer._layers).length > 0;
      }
      return false;
    });

    expect(hasRoutes).toBe(true);
  });

  test('should enable Heatmap layer and display heatmap', async ({ page }) => {
    await waitForMap(page);
    await enableLayer(page, 'Heatmap');

    const hasHeatmap = await page.locator('.leaflet-heatmap-layer').isVisible();
    expect(hasHeatmap).toBe(true);
  });

  test('should enable Fog of War layer and display fog', async ({ page }) => {
    await waitForMap(page);
    await enableLayer(page, 'Fog of War');

    const hasFog = await page.evaluate(() => {
      const fogCanvas = document.getElementById('fog');
      return fogCanvas && fogCanvas instanceof HTMLCanvasElement;
    });

    expect(hasFog).toBe(true);
  });

  test('should enable Areas layer and display areas', async ({ page }) => {
    await waitForMap(page);

    // Check if there are any points in the map - areas need location data
    const hasPoints = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      if (controller?.pointsLayer?._layers) {
        return Object.keys(controller.pointsLayer._layers).length > 0;
      }
      return false;
    });

    if (!hasPoints) {
      console.log('No points found - skipping areas test');
      return;
    }

    const hasAreasLayer = await page.evaluate(() => {
      const mapElement = document.querySelector('#map');
      const app = window.Stimulus;
      const controller = app?.getControllerForElementAndIdentifier(mapElement, 'maps');
      return controller?.areasLayer !== null && controller?.areasLayer !== undefined;
    });

    expect(hasAreasLayer).toBe(true);
  });

  test('should enable Suggested Visits layer', async ({ page }) => {
    await waitForMap(page);
    // Suggested Visits are now under Visits > Suggested in the tree
    await enableLayer(page, 'Suggested');

    const hasSuggestedVisits = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      return controller?.visitsManager?.visitCircles !== null &&
        controller?.visitsManager?.visitCircles !== undefined;
    });

    expect(hasSuggestedVisits).toBe(true);
  });

  test('should enable Confirmed Visits layer', async ({ page }) => {
    await waitForMap(page);
    // Confirmed Visits are now under Visits > Confirmed in the tree
    await enableLayer(page, 'Confirmed');

    const hasConfirmedVisits = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      return controller?.visitsManager?.confirmedVisitCircles !== null &&
        controller?.visitsManager?.confirmedVisitCircles !== undefined;
    });

    expect(hasConfirmedVisits).toBe(true);
  });

  test('should enable Scratch Map layer and display visited countries', async ({ page }) => {
    await waitForMap(page);

    // Check if there are any points - scratch map needs location data
    const hasPoints = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      if (controller?.pointsLayer?._layers) {
        return Object.keys(controller.pointsLayer._layers).length > 0;
      }
      return false;
    });

    if (!hasPoints) {
      console.log('No points found - skipping scratch map test');
      return;
    }

    await enableLayer(page, 'Scratch Map');

    // Wait a bit for the layer to load country borders
    await page.waitForTimeout(2000);

    // Verify scratch layer exists and has been initialized
    const hasScratchLayer = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');

      // Check if scratchLayerManager exists
      if (!controller?.scratchLayerManager) return false;

      // Check if scratch layer was created
      const scratchLayer = controller.scratchLayerManager.getLayer();
      return scratchLayer !== null && scratchLayer !== undefined;
    });

    expect(hasScratchLayer).toBe(true);
  });

  test('should remember enabled layers across page reloads', async ({ page }) => {
    await waitForMap(page);

    // Check if there are any points - needed for this test to be meaningful
    const hasPoints = await page.evaluate(() => {
      const controller = window.Stimulus?.controllers.find(c => c.identifier === 'maps');
      if (controller?.pointsLayer?._layers) {
        return Object.keys(controller.pointsLayer._layers).length > 0;
      }
      return false;
    });

    if (!hasPoints) {
      console.log('No points found - skipping layer persistence test');
      return;
    }

    // Enable multiple layers
    await enableLayer(page, 'Points');
    await enableLayer(page, 'Routes');
    await enableLayer(page, 'Heatmap');
    await page.waitForTimeout(500);

    // Get current layer states
    const getLayerStates = () => page.evaluate(() => {
      const layers = {};
      // Use tree structure selectors
      document.querySelectorAll('.leaflet-layerstree-header-label input[type="checkbox"]').forEach(checkbox => {
        const nameSpan = checkbox.closest('.leaflet-layerstree-header').querySelector('.leaflet-layerstree-header-name');
        if (nameSpan) {
          const label = nameSpan.textContent.trim();
          layers[label] = checkbox.checked;
        }
      });
      return layers;
    });

    const layersBeforeReload = await getLayerStates();

    // Reload the page
    await page.reload();
    await closeOnboardingModal(page);
    await waitForMap(page);
    await page.waitForTimeout(1000); // Wait for layers to restore

    // Get layer states after reload
    const layersAfterReload = await getLayerStates();

    // Verify Points, Routes, and Heatmap are still enabled
    expect(layersAfterReload['Points']).toBe(true);
    expect(layersAfterReload['Routes']).toBe(true);
    expect(layersAfterReload['Heatmap']).toBe(true);

    // Verify layer states match before and after
    expect(layersAfterReload).toEqual(layersBeforeReload);
  });
});
