import React, { useState, useEffect, useRef } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import apiService from './services/api';
import './styles/App.css';

const APP = () => {
  const mapContainerRef = useRef(null);
  const mapRef = useRef(null);
  const startMarkerRef = useRef(null);
  const [selectedPoint, setSelectedPoint] = useState({ lat: 51.5074, lon: -0.1278 });
  const [direction, setDirection] = useState(45);
  const [lineOfSightData, setLineOfSightData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [mapStyle, setMapStyle] = useState('light'); // 'light' or 'dark'
  const [tolerance, setTolerance] = useState(50);

  useEffect(() => {
    // Initialize MapLibre map
    mapRef.current = new maplibregl.Map({
      container: mapContainerRef.current,
      style: getMapStyle(mapStyle),
      center: [-0.1278, 51.5074], // London
      zoom: 3,
      pitch: 0
    });

    mapRef.current.on('load', () => {
      console.log('Map loaded successfully');
      
      // Initialize start marker
      startMarkerRef.current = new maplibregl.Marker({ color: '#FF6B6B' })
        .setLngLat([selectedPoint.lon, selectedPoint.lat])
        .addTo(mapRef.current);

      // Initialize preview line source and layer
      mapRef.current.addSource('preview-line', {
        type: 'geojson',
        data: {
          type: 'Feature',
          geometry: {
            type: 'LineString',
            coordinates: []
          }
        }
      });

      mapRef.current.addLayer({
        id: 'preview-line',
        type: 'line',
        source: 'preview-line',
        paint: {
          'line-color': '#FF6B6B',
          'line-width': 2,
          'line-dasharray': [2, 2]
        }
      });

      updatePreviewLine(selectedPoint, direction);
    });

    mapRef.current.on('click', (e) => {
      const { lng, lat } = e.lngLat;
      setSelectedPoint({ lat, lon: lng });
      
      if (startMarkerRef.current) {
        startMarkerRef.current.setLngLat([lng, lat]);
      }

      // Clear previous final line when moving start point
      if (mapRef.current.getSource('line-of-sight')) {
        mapRef.current.removeLayer('line-of-sight');
        mapRef.current.removeSource('line-of-sight');
      }
    });

    return () => {
      mapRef.current.remove();
    };
  }, []);

  useEffect(() => {
    // Update preview whenever point or direction changes
    if (mapRef.current && mapRef.current.isStyleLoaded()) {
      updatePreviewLine(selectedPoint, direction);
    }
  }, [selectedPoint, direction]);

  const updatePreviewLine = (point, bearing) => {
    const map = mapRef.current;
    if (!map || !map.getSource('preview-line')) return;

    // Generate 50 points along a 5000km great circle path for a smooth curve
    const path = [];
    const steps = 50;
    const totalDistance = 5000;

    for (let i = 0; i <= steps; i++) {
      const dist = (totalDistance * i) / steps;
      path.push(calculateDestination(point.lat, point.lon, bearing, dist));
    }
    
    map.getSource('preview-line').setData({
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: path.map(p => [p.lon, p.lat])
      }
    });
  };

  // Helper to calculate destination point given start, bearing, and distance (km)
  const calculateDestination = (lat, lon, bearing, distance) => {
    const R = 6371; // Earth's radius in km
    const brng = (bearing * Math.PI) / 180;
    const φ1 = (lat * Math.PI) / 180;
    const λ1 = (lon * Math.PI) / 180;
    const δ = distance / R;

    const φ2 = Math.asin(
      Math.sin(φ1) * Math.cos(δ) +
        Math.cos(φ1) * Math.sin(δ) * Math.cos(brng)
    );
    const λ2 =
      λ1 +
      Math.atan2(
        Math.sin(brng) * Math.sin(δ) * Math.cos(φ1),
        Math.cos(δ) - Math.sin(φ1) * Math.sin(φ2)
      );

    return {
      lat: (φ2 * 180) / Math.PI,
      lon: (((λ2 * 180) / Math.PI + 540) % 360) - 180
    };
  };

  useEffect(() => {
    // Update map style when toggle changes
    if (mapRef.current) {
      mapRef.current.setStyle(getMapStyle(mapStyle));
    }
  }, [mapStyle]);

  const getMapStyle = (style) => {
    return style === 'dark' 
      ? 'https://demotiles.maplibre.org/style.json' 
      : 'https://demotiles.maplibre.org/style.json'; // Using same for now, can be customized
  };

  const handleShowLineOfSight = async () => {
    setLoading(true);
    try {
      const response = await apiService.getLineOfSight(
        selectedPoint.lat, 
        selectedPoint.lon, 
        direction, 
        tolerance
      );
      
      setLineOfSightData(response.data);
      renderLineOnMap(response.data);
    } catch (error) {
      console.error('Error fetching line of sight:', error);
    } finally {
      setLoading(false);
    }
  };

  const renderLineOnMap = (data) => {
    const map = mapRef.current;
    if (!map) return;

    // Clear existing line
    if (map.getSource('line-of-sight')) {
      map.removeLayer('line-of-sight');
      map.removeSource('line-of-sight');
    }

    // Add line source
    map.addSource('line-of-sight', {
      type: 'geojson',
      data: {
        type: 'Feature',
        properties: {},
        geometry: {
          type: 'LineString',
          coordinates: data.line_coordinates.map(coord => [coord.lon, coord.lat])
        }
      }
    });

    // Add line layer
    map.addLayer({
      id: 'line-of-sight',
      type: 'line',
      source: 'line-of-sight',
      layout: {
        'line-join': 'round',
        'line-cap': 'round'
      },
      paint: {
        'line-color': '#FF6B6B',
        'line-width': 4,
        'line-opacity': 0.8
      }
    });

    // Add city markers
    data.conurbations.forEach((city, index) => {
      const markerId = `city-${index}`;
      
      // Create marker element
      const el = document.createElement('div');
      el.className = 'city-marker';
      el.innerHTML = `
        <div class="marker-dot"></div>
        <div class="marker-label">${city.name}</div>
        <div class="marker-pop">${(city.population / 1000000).toFixed(1)}M</div>
      `;

      // Add marker to map
      new maplibregl.Marker(el)
        .setLngLat([city.lon, city.lat])
        .setPopup(new maplibregl.Popup().setHTML(
          `<strong>${city.name}</strong><br/>Population: ${city.population.toLocaleString()}<br/>Distance: ${city.distance_km} km`
        ))
        .addTo(map);
    });

    // Fit bounds to show line
    const bounds = new maplibregl.LngLatBounds();
    data.line_coordinates.forEach(coord => {
      bounds.extend([coord.lon, coord.lat]);
    });
    map.fitBounds(bounds, { padding: 50 });
  };

  return (
    <div className="app-container">
      <div className="map-container" ref={mapContainerRef}></div>
      
      <div className="controls">
        <div className="control-group">
          <h3>Line of Sight Settings</h3>
          
          <div className="setting-row">
            <label>Start Point:</label>
            <span>{selectedPoint.lat.toFixed(4)}, {selectedPoint.lon.toFixed(4)}</span>
          </div>

          <div className="setting-row">
            <label>Direction (0-360°):</label>
            <input 
              type="range" 
              min="0" 
              max="360" 
              value={direction} 
              onChange={(e) => setDirection(parseInt(e.target.value))}
            />
            <span>{direction}°</span>
          </div>

          <div className="setting-row">
            <label>Fuzziness Tolerance (km):</label>
            <input 
              type="number" 
              value={tolerance} 
              onChange={(e) => setTolerance(parseInt(e.target.value))}
              min="10"
              max="200"
            />
            <span>{tolerance} km</span>
          </div>

          <div className="setting-row">
            <label>Map Style:</label>
            <button onClick={() => setMapStyle('light')}>Light</button>
            <button onClick={() => setMapStyle('dark')}>Dark</button>
          </div>

          <button 
            className="action-btn" 
            onClick={handleShowLineOfSight} 
            disabled={loading}
          >
            {loading ? 'Calculating...' : '📡 Show Line of Sight'}
          </button>
        </div>

        {lineOfSightData && (
          <div className="results-panel">
            <h3>Conurbations Found ({lineOfSightData.conurbations.length})</h3>
            <table>
              <thead>
                <tr>
                  <th>#</th>
                  <th>City</th>
                  <th>Population</th>
                  <th>Distance</th>
                </tr>
              </thead>
              <tbody>
                {lineOfSightData.conurbations.slice(0, 10).map((city, index) => (
                  <tr key={city.id}>
                    <td>{index + 1}</td>
                    <td>{city.name}</td>
                    <td>{(city.population / 1000000).toFixed(1)}M</td>
                    <td>{city.distance_km} km</td>
                  </tr>
                ))}
              </tbody>
            </table>
            {lineOfSightData.conurbations.length > 10 && (
              <p className="more-info">... and {lineOfSightData.conurbations.length - 10} more cities</p>
            )}
          </div>
        )}

        <div className="instructions">
          <h3>How to Use</h3>
          <ol>
            <li>Click anywhere on the map to select a starting point</li>
            <li>Adjust the direction using the slider (0-360°)</li>
            <li>Set your fuzziness tolerance (how close cities must be to the line)</li>
            <li>Click "Show Line of Sight" to visualize the path and cities</li>
          </ol>
        </div>
      </div>
    </div>
  );
};

export default APP;
