import { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css';
import 'react-leaflet-cluster/dist/assets/MarkerCluster.css';
import 'react-leaflet-cluster/dist/assets/MarkerCluster.Default.css';
import FileUpload from './components/FileUpload';
import FilterPanel from './components/FilterPanel';
import MapDisplay from './components/MapDisplay';
import ErrorBoundary from './components/ErrorBoundary';
import PlzSelector from './components/PlzSelector';

// Define types for our state
export interface FilterOptions {
  [key: string]: string[];
}

export interface TooltipColumn {
  id: string;
  name: string;
  visible: boolean;
}

export interface HeatmapPoint {
  plz: string;
  lat: number;
  lon: number;
  count: number;
  attributes_summary?: Record<string, string[]>;
}

export interface StaffLocation {
  name: string;
  plz: string;
  lat: number;
  lon: number;
}

export interface StaffData {
  sales: StaffLocation[];
  technicians: StaffLocation[];
}

export type MapMode = 'points' | 'heatmap';

function App() {
  const [filters, setFilters] = useState<FilterOptions>({});
  const [heatmapData, setHeatmapData] = useState<HeatmapPoint[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [radiusMultiplier, setRadiusMultiplier] = useState(1);
  const [viewMode, setViewMode] = useState<MapMode>('points');
  
  const [plzColumnNeeded, setPlzColumnNeeded] = useState(false);
  const [availableColumns, setAvailableColumns] = useState<string[]>([]);
  const [tooltipColumns, setTooltipColumns] = useState<TooltipColumn[]>([]);

  const [staffData, setStaffData] = useState<StaffData>({ sales: [], technicians: [] });
  const [showSales, setShowSales] = useState(false);
  const [showTechnicians, setShowTechnicians] = useState(false);
  const [travelTime, setTravelTime] = useState(60); // In minutes
  const [averageSpeed, setAverageSpeed] = useState(80); // In km/h
  const [isochrones, setIsochrones] = useState<Record<string, any>>({});
  const [orsError, setOrsError] = useState<string | null>(null);

  // Derived travel radius in km (fallback)
  const travelRadius = (travelTime / 60) * averageSpeed;

  useEffect(() => {
    const fetchStaffLocations = async () => {
      try {
        const response = await axios.get('/heatmap/api/staff-locations');
        setStaffData(response.data);
      } catch (err) {
        console.error("Failed to fetch staff locations:", err);
      }
    };
    fetchStaffLocations();
  }, []);

  // Fetch isochrones when settings change
  useEffect(() => {
    if (!showSales && !showTechnicians) return;

    const fetchAllIsochrones = async () => {
      const activeStaff = [
        ...(showSales ? staffData.sales : []),
        ...(showTechnicians ? staffData.technicians : [])
      ];

      if (activeStaff.length === 0) return;

      const newIsochrones: Record<string, any> = { ...isochrones };
      let anyOrsError = false;

      for (const person of activeStaff) {
        // Skip if already fetched for this person and time
        if (newIsochrones[person.name] && newIsochrones[person.name].minutes === travelTime) {
            continue;
        }

        try {
          const response = await axios.get('/heatmap/api/isochrones', {
            params: { lat: person.lat, lon: person.lon, minutes: travelTime }
          });
          
          if (response.data.simulated || response.data.error) {
            setOrsError("OpenRouteService API Key missing or invalid. Showing circular fallback.");
            anyOrsError = true;
            break;
          }
          
          newIsochrones[person.name] = {
              data: response.data,
              minutes: travelTime
          };
        } catch (err) {
          console.error(`Failed to fetch isochrone for ${person.name}:`, err);
          // Don't set anyOrsError here, just let this one person use the fallback
        }
      }

      setIsochrones(newIsochrones);
      if (!anyOrsError) setOrsError(null);
    };

    const timer = setTimeout(fetchAllIsochrones, 800); // Debounce
    return () => clearTimeout(timer);
  }, [travelTime, showSales, showTechnicians, staffData]);

  const handleUploadSuccess = (response: any) => {
    setError(null);
    if (response.plz_column_needed) {
      setAvailableColumns(response.columns);
      setPlzColumnNeeded(true);
      setFilters({});
      setHeatmapData([]);
      setTooltipColumns([]);
    } else {
      setPlzColumnNeeded(false);
      const newFilters = response.filters;
      setFilters(newFilters);
      // Initialize tooltip columns based on filters
      setTooltipColumns(Object.keys(newFilters).map(name => ({ id: name, name, visible: true })));
      setHeatmapData([]); // Clear previous heatmap data
      // Automatically fetch data with no filters on successful upload
      // Pass initial tooltip config
      handleFilterChange({}, Object.keys(newFilters).map(name => ({ id: name, name, visible: true })));
    }
  };

  const handlePlzColumnSubmit = async (selectedColumn: string) => {
    setIsLoading(true);
    setError(null);
    try {
      const response = await axios.post('/heatmap/api/set-plz-column', {
        plz_column: selectedColumn,
      });
      handleUploadSuccess(response.data); // Re-use the success handler
    } catch (error: any) {
        if (axios.isAxiosError(error) && error.response) {
            setError(`Failed to set PLZ column: ${error.response.data.detail || error.message}`);
        }
        else {
            setError(`Failed to set PLZ column: ${error.message}`);
        }
    }
    finally {
        setIsLoading(false);
    }
  };

  const handleFilterChange = async (selectedFilters: FilterOptions, currentTooltipConfig: TooltipColumn[]) => {
    setIsLoading(true);
    setError(null);
    try {
      const response = await axios.post('/heatmap/api/heatmap', {
        filters: selectedFilters,
        tooltip_config: currentTooltipConfig, // Pass tooltip config to backend
      });
      setHeatmapData(response.data);
    } catch (error: any) {
        if (axios.isAxiosError(error) && error.response) {
            setError(`Failed to fetch heatmap data: ${error.response.data.detail || error.message}`);
        }
        else {
            setError(`Failed to fetch heatmap data: ${error.message}`);
        }
      setHeatmapData([]); // Clear data on error
    }
    finally {
      setIsLoading(false);
    }
  };
  
  // Need to re-fetch data when tooltip config changes. 
  // Optimization: In a real app, we might debounce this or add an "Apply" button for sorting.
  // For now, let's keep it manual via the "Apply Filters" button in the FilterPanel to avoid excessive API calls while dragging.
  // The FilterPanel calls onFilterChange when "Apply" is clicked, passing both filters and the current tooltipColumns.

  return (
    <ErrorBoundary>
        <div className="App">
        <header className="App-header">
            <h1>German PLZ Heatmap Tool</h1>
        </header>
        <main className="App-main">
            <div className="control-panel">
              <FileUpload
                  onUploadSuccess={handleUploadSuccess}
                  setIsLoading={setIsLoading}
                  setError={setError}
              />
              {plzColumnNeeded ? (
                <PlzSelector
                  columns={availableColumns}
                  onSubmit={handlePlzColumnSubmit}
                  isLoading={isLoading}
                />
              ) : (
                <>
                  <FilterPanel
                      filters={filters}
                      tooltipColumns={tooltipColumns}
                      setTooltipColumns={setTooltipColumns}
                      onFilterChange={(selectedFilters) => handleFilterChange(selectedFilters, tooltipColumns)}
                      isLoading={isLoading}
                  />
                  <div className="map-controls" style={{ marginTop: '20px', paddingTop: '20px', borderTop: '1px solid #555' }}>
                    <h3>Map Settings</h3>
                    <div className="toggle-switch" style={{ marginBottom: '15px' }}>
                      <label>
                        <input type="radio" value="points" checked={viewMode === 'points'} onChange={() => setViewMode('points')} />
                        Points
                      </label>
                      <label>
                        <input type="radio" value="heatmap" checked={viewMode === 'heatmap'} onChange={() => setViewMode('heatmap')} />
                        Heatmap
                      </label>
                    </div>

                    <div className="staff-toggles" style={{ marginBottom: '15px' }}>
                      <label style={{ display: 'block', marginBottom: '5px' }}>
                        <input type="checkbox" checked={showSales} onChange={(e) => setShowSales(e.target.checked)} />
                        Show Sales Reps
                      </label>
                      <label style={{ display: 'block', marginBottom: '15px' }}>
                        <input type="checkbox" checked={showTechnicians} onChange={(e) => setShowTechnicians(e.target.checked)} />
                        Show Technicians
                      </label>
                    </div>

                    {(showSales || showTechnicians) && (
                      <div className="radius-control" style={{ marginBottom: '20px', padding: '10px', backgroundColor: '#444', borderRadius: '4px' }}>
                        <div style={{ marginBottom: '10px' }}>
                          <label htmlFor="travel-time">Travel Time: {travelTime} min (max 60)</label>
                          <input
                            type="range"
                            id="travel-time"
                            min="15"
                            max="60"
                            step="5"
                            value={travelTime}
                        </div>
                        {orsError ? (
                           <>
                            <div style={{ marginBottom: '10px' }}>
                                <label htmlFor="avg-speed">Avg. Speed: {averageSpeed} km/h</label>
                                <input
                                    type="range"
                                    id="avg-speed"
                                    min="30"
                                    max="120"
                                    step="5"
                                    value={averageSpeed}
                                    onChange={(e) => setAverageSpeed(parseInt(e.target.value))}
                                    style={{ width: '100%' }}
                                />
                            </div>
                            <div style={{ fontSize: '0.8em', color: '#ffcc00', marginBottom: '5px' }}>
                                {orsError}
                            </div>
                            <div style={{ fontSize: '0.9em', color: '#ccc', textAlign: 'center', borderTop: '1px solid #666', paddingTop: '5px' }}>
                                Resulting Radius: <strong>{travelRadius.toFixed(1)} km</strong>
                            </div>
                           </>
                        ) : (
                            <div style={{ fontSize: '0.8em', color: '#4CAF50' }}>
                                Using real road data (OpenRouteService)
                            </div>
                        )}
                      </div>
                    )}

                    <label htmlFor="radius-slider">Marker Size: {radiusMultiplier.toFixed(1)}x</label>
                    <input
                      type="range"
                      id="radius-slider"
                      min="0.1"
                      max="5"
                      step="0.1"
                      value={radiusMultiplier}
                      onChange={(e) => setRadiusMultiplier(parseFloat(e.target.value))}
                      style={{ width: '100%' }}
                      disabled={viewMode === 'heatmap'}
                    />
                  </div>
                </>
              )}
            </div>
            <div className="map-container">
            {isLoading ? (
                <p>Loading map data...</p>
            ) : error ? (
                <p className="error">{error}</p>
            ) : (
                <MapDisplay
                heatmapData={heatmapData}
                radiusMultiplier={radiusMultiplier}
                viewMode={viewMode}
                tooltipColumns={tooltipColumns}
                staffData={staffData}
                showSales={showSales}
                showTechnicians={showTechnicians}
                travelRadius={travelRadius}
                isochrones={isochrones}
                />
            )}
            </div>
        </main>
        </div>
    </ErrorBoundary>
  );
}

export default App;
