import { useEffect, useState, useCallback } from 'react';
import type { Site } from '@/types/index.ts';
import { useSitesStore } from '@/store/sites.ts';
import { useCoverageStore } from '@/store/coverage.ts';
import { useSettingsStore } from '@/store/settings.ts';
import { RFCalculator } from '@/rf/calculator.ts';
import { useToastStore } from '@/components/ui/Toast.tsx';
import { useKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts.ts';
import MapView from '@/components/map/Map.tsx';
import Heatmap from '@/components/map/Heatmap.tsx';
import Legend from '@/components/map/Legend.tsx';
import SiteList from '@/components/panels/SiteList.tsx';
import SiteForm from '@/components/panels/SiteForm.tsx';
import ExportPanel from '@/components/panels/ExportPanel.tsx';
import ProjectPanel from '@/components/panels/ProjectPanel.tsx';
import CoverageStats from '@/components/panels/CoverageStats.tsx';
import SiteImportExport from '@/components/panels/SiteImportExport.tsx';
import ToastContainer from '@/components/ui/Toast.tsx';
import ThemeToggle from '@/components/ui/ThemeToggle.tsx';
import Button from '@/components/ui/Button.tsx';

const calculator = new RFCalculator();

export default function App() {
  const loadSites = useSitesStore((s) => s.loadSites);
  const sites = useSitesStore((s) => s.sites);
  const setPlacingMode = useSitesStore((s) => s.setPlacingMode);

  const coverageResult = useCoverageStore((s) => s.result);
  const isCalculating = useCoverageStore((s) => s.isCalculating);
  const settings = useCoverageStore((s) => s.settings);
  const setResult = useCoverageStore((s) => s.setResult);
  const setIsCalculating = useCoverageStore((s) => s.setIsCalculating);
  const heatmapVisible = useCoverageStore((s) => s.heatmapVisible);

  const addToast = useToastStore((s) => s.addToast);

  const showTerrain = useSettingsStore((s) => s.showTerrain);
  const terrainOpacity = useSettingsStore((s) => s.terrainOpacity);
  const setTerrainOpacity = useSettingsStore((s) => s.setTerrainOpacity);
  const showGrid = useSettingsStore((s) => s.showGrid);
  const setShowGrid = useSettingsStore((s) => s.setShowGrid);
  const measurementMode = useSettingsStore((s) => s.measurementMode);
  const setMeasurementMode = useSettingsStore((s) => s.setMeasurementMode);
  const showElevationInfo = useSettingsStore((s) => s.showElevationInfo);
  const setShowElevationInfo = useSettingsStore((s) => s.setShowElevationInfo);
  const showElevationOverlay = useSettingsStore((s) => s.showElevationOverlay);
  const setShowElevationOverlay = useSettingsStore((s) => s.setShowElevationOverlay);

  const [showForm, setShowForm] = useState(false);
  const [editSite, setEditSite] = useState<Site | null>(null);
  const [pendingLocation, setPendingLocation] = useState<{
    lat: number;
    lon: number;
  } | null>(null);
  const [panelCollapsed, setPanelCollapsed] = useState(false);
  const [showShortcuts, setShowShortcuts] = useState(false);

  // Load sites from IndexedDB on mount
  useEffect(() => {
    loadSites();
  }, [loadSites]);

  // Handle map click -> open form with coordinates
  const handleMapClick = useCallback(
    (lat: number, lon: number) => {
      setPendingLocation({ lat, lon });
      setEditSite(null);
      setShowForm(true);
      setPlacingMode(false);
    },
    [setPlacingMode]
  );

  const handleEditSite = useCallback((site: Site) => {
    setEditSite(site);
    setPendingLocation(null);
    setShowForm(true);
  }, []);

  const handleAddManual = useCallback(() => {
    setEditSite(null);
    setPendingLocation(null);
    setShowForm(true);
  }, []);

  const handleCloseForm = useCallback(() => {
    setShowForm(false);
    setEditSite(null);
    setPendingLocation(null);
  }, []);

  // Calculate coverage (with better error handling)
  const handleCalculate = useCallback(async () => {
    const currentSites = useSitesStore.getState().sites;
    if (currentSites.length === 0) {
      addToast('Add at least one site to calculate coverage', 'error');
      return;
    }

    const currentSettings = useCoverageStore.getState().settings;

    // Validation
    if (currentSettings.radius > 100) {
      addToast('Radius too large (max 100km)', 'error');
      return;
    }
    if (currentSettings.resolution < 50) {
      addToast('Resolution too fine (min 50m)', 'error');
      return;
    }

    setIsCalculating(true);
    try {
      const latitudes = currentSites.map((s) => s.lat);
      const longitudes = currentSites.map((s) => s.lon);
      const radiusDeg = currentSettings.radius / 111;
      const avgLat =
        (Math.max(...latitudes) + Math.min(...latitudes)) / 2;
      const lonRadiusDeg =
        radiusDeg / Math.cos((avgLat * Math.PI) / 180);

      const bounds = {
        north: Math.max(...latitudes) + radiusDeg,
        south: Math.min(...latitudes) - radiusDeg,
        east: Math.max(...longitudes) + lonRadiusDeg,
        west: Math.min(...longitudes) - lonRadiusDeg,
      };

      const result = await calculator.calculateCoverage(
        currentSites,
        bounds,
        currentSettings
      );

      setResult(result);

      if (result.points.length === 0) {
        addToast(
          'No coverage points found. Try increasing radius or lowering threshold.',
          'warning'
        );
      } else {
        addToast(
          `Calculated ${result.totalPoints.toLocaleString()} points in ${(result.calculationTime / 1000).toFixed(1)}s`,
          'success'
        );
      }
    } catch (err) {
      console.error('Coverage calculation error:', err);
      const msg = err instanceof Error ? err.message : 'Unknown error';

      let userMessage = 'Calculation failed';
      if (msg.includes('timeout')) {
        userMessage = 'Calculation timeout. Try reducing radius or increasing resolution.';
      } else if (msg.includes('worker') || msg.includes('Worker')) {
        userMessage = 'Web Worker error. Please refresh the page.';
      } else {
        userMessage = `Calculation failed: ${msg}`;
      }

      addToast(userMessage, 'error');
    } finally {
      setIsCalculating(false);
    }
  }, [setIsCalculating, setResult, addToast]);

  // Keyboard shortcuts
  useKeyboardShortcuts({
    onCalculate: handleCalculate,
    onCloseForm: handleCloseForm,
  });

  return (
    <div className="h-screen w-screen flex flex-col bg-gray-100 dark:bg-dark-bg">
      {/* Header */}
      <header className="bg-slate-800 dark:bg-slate-900 text-white px-4 py-2 flex items-center justify-between flex-shrink-0 z-10">
        <div className="flex items-center gap-2">
          <span className="text-base font-bold">RFCP</span>
          <span className="text-xs text-slate-400 hidden sm:inline">
            RF Coverage Planner
          </span>
        </div>
        <div className="flex items-center gap-3">
          <ThemeToggle />
          <button
            onClick={() => setShowShortcuts(!showShortcuts)}
            className="text-slate-400 hover:text-white text-sm hidden sm:inline"
            title="Keyboard shortcuts"
          >
            ?
          </button>
          <Button
            size="sm"
            variant={isCalculating ? 'secondary' : 'primary'}
            onClick={handleCalculate}
            disabled={isCalculating || sites.length === 0}
          >
            {isCalculating ? (
              <span className="flex items-center gap-1">
                <span className="animate-spin inline-block w-3 h-3 border-2 border-white border-t-transparent rounded-full" />
                Calculating...
              </span>
            ) : (
              'Calculate Coverage'
            )}
          </Button>
          <button
            onClick={() => setPanelCollapsed(!panelCollapsed)}
            className="text-slate-400 hover:text-white text-sm sm:hidden min-w-[44px] min-h-[44px] flex items-center justify-center"
          >
            {panelCollapsed ? 'Show' : 'Hide'}
          </button>
        </div>
      </header>

      {/* Shortcuts modal */}
      {showShortcuts && (
        <div
          className="fixed inset-0 z-[9000] bg-black/40 flex items-center justify-center"
          onClick={() => setShowShortcuts(false)}
        >
          <div
            className="bg-white dark:bg-dark-surface rounded-lg shadow-xl p-5 max-w-sm mx-4 border border-gray-200 dark:border-dark-border"
            onClick={(e) => e.stopPropagation()}
          >
            <h3 className="font-semibold text-gray-800 dark:text-dark-text mb-3">
              Keyboard Shortcuts
            </h3>
            <ul className="space-y-2 text-sm text-gray-600 dark:text-dark-muted">
              <li className="flex justify-between gap-4">
                <span>Calculate coverage</span>
                <kbd className="px-1.5 py-0.5 bg-gray-100 dark:bg-dark-border rounded text-xs font-mono">Ctrl+Enter</kbd>
              </li>
              <li className="flex justify-between gap-4">
                <span>New site (place mode)</span>
                <kbd className="px-1.5 py-0.5 bg-gray-100 dark:bg-dark-border rounded text-xs font-mono">Ctrl+N</kbd>
              </li>
              <li className="flex justify-between gap-4">
                <span>Cancel / Close</span>
                <kbd className="px-1.5 py-0.5 bg-gray-100 dark:bg-dark-border rounded text-xs font-mono">Esc</kbd>
              </li>
              <li className="flex justify-between gap-4">
                <span>Toggle heatmap</span>
                <kbd className="px-1.5 py-0.5 bg-gray-100 dark:bg-dark-border rounded text-xs font-mono">H</kbd>
              </li>
            </ul>
            <button
              onClick={() => setShowShortcuts(false)}
              className="mt-4 w-full py-2 text-sm bg-gray-100 dark:bg-dark-border dark:text-dark-text rounded-md hover:bg-gray-200 dark:hover:bg-dark-muted transition-colors"
            >
              Close
            </button>
          </div>
        </div>
      )}

      {/* Main content */}
      <div className="flex-1 flex overflow-hidden relative">
        {/* Map */}
        <div className="flex-1 relative">
          <MapView onMapClick={handleMapClick} onEditSite={handleEditSite}>
            {coverageResult && (
              <Heatmap
                points={coverageResult.points}
                visible={heatmapVisible}
                opacity={settings.heatmapOpacity}
              />
            )}
          </MapView>
          <Legend />
        </div>

        {/* Side panel */}
        <div
          className={`${
            panelCollapsed ? 'hidden' : 'flex'
          } flex-col w-full sm:w-80 lg:w-96 bg-gray-50 dark:bg-dark-bg border-l border-gray-200 dark:border-dark-border
            overflow-y-auto absolute sm:relative inset-0 sm:inset-auto z-[1001]`}
        >
          {/* Mobile drag handle + close */}
          <div className="sm:hidden flex flex-col items-center pt-2 pb-1">
            <div className="w-12 h-1 bg-gray-300 dark:bg-dark-border rounded-full mb-2" />
            <button
              onClick={() => setPanelCollapsed(true)}
              className="text-gray-500 dark:text-dark-muted hover:text-gray-700 dark:hover:text-dark-text text-sm min-h-[44px]"
            >
              Close Panel
            </button>
          </div>

          <div className="p-3 space-y-3 flex-1 overflow-y-auto">
            {/* Site list */}
            <SiteList onEditSite={handleEditSite} onAddSite={handleAddManual} />

            {/* Site form */}
            {showForm && (
              <SiteForm
                editSite={editSite}
                pendingLocation={pendingLocation}
                onClose={handleCloseForm}
                onClearPending={() => setPendingLocation(null)}
                onCalculate={handleCalculate}
              />
            )}

            {/* Coverage settings */}
            <div className="bg-white dark:bg-dark-surface border border-gray-200 dark:border-dark-border rounded-lg shadow-sm p-4 space-y-3">
              <h3 className="text-sm font-semibold text-gray-800 dark:text-dark-text">
                Coverage Settings
              </h3>
              <div className="space-y-2">
                <div>
                  <label className="text-xs text-gray-500 dark:text-dark-muted">
                    Radius: {settings.radius} km
                  </label>
                  <input
                    type="range"
                    min={1}
                    max={100}
                    step={5}
                    value={settings.radius}
                    onChange={(e) =>
                      useCoverageStore
                        .getState()
                        .updateSettings({ radius: Number(e.target.value) })
                    }
                    className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600"
                  />
                </div>
                <div>
                  <label className="text-xs text-gray-500 dark:text-dark-muted">
                    Resolution: {settings.resolution}m
                  </label>
                  <input
                    type="range"
                    min={50}
                    max={500}
                    step={50}
                    value={settings.resolution}
                    onChange={(e) =>
                      useCoverageStore
                        .getState()
                        .updateSettings({ resolution: Number(e.target.value) })
                    }
                    className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600"
                  />
                </div>
                <div>
                  <label className="text-xs text-gray-500 dark:text-dark-muted">
                    Min Signal: {settings.rsrpThreshold} dBm
                  </label>
                  <input
                    type="range"
                    min={-140}
                    max={-70}
                    step={5}
                    value={settings.rsrpThreshold}
                    onChange={(e) =>
                      useCoverageStore
                        .getState()
                        .updateSettings({
                          rsrpThreshold: Number(e.target.value),
                        })
                    }
                    className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600"
                  />
                </div>
                <div>
                  <label className="text-xs text-gray-500 dark:text-dark-muted">
                    Heatmap Opacity: {Math.round(settings.heatmapOpacity * 100)}%
                  </label>
                  <input
                    type="range"
                    min={0.3}
                    max={1.0}
                    step={0.1}
                    value={settings.heatmapOpacity}
                    onChange={(e) =>
                      useCoverageStore
                        .getState()
                        .updateSettings({
                          heatmapOpacity: Number(e.target.value),
                        })
                    }
                    className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600"
                  />
                </div>
                <div>
                  <label className="text-xs text-gray-500 dark:text-dark-muted">
                    Terrain Opacity: {Math.round(terrainOpacity * 100)}%
                    {!showTerrain && ' (disabled)'}
                  </label>
                  <input
                    type="range"
                    min={0.1}
                    max={1.0}
                    step={0.1}
                    value={terrainOpacity}
                    onChange={(e) => setTerrainOpacity(Number(e.target.value))}
                    disabled={!showTerrain}
                    className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600 disabled:opacity-40"
                  />
                </div>
              </div>
            </div>

            {/* Map Tools */}
            <div className="bg-white dark:bg-dark-surface border border-gray-200 dark:border-dark-border rounded-lg shadow-sm p-4 space-y-3">
              <h3 className="text-sm font-semibold text-gray-800 dark:text-dark-text">
                Map Tools
              </h3>
              <div className="space-y-2">
                <label className="flex items-center gap-2 cursor-pointer text-sm text-gray-700 dark:text-dark-text">
                  <input
                    type="checkbox"
                    checked={showGrid}
                    onChange={(e) => setShowGrid(e.target.checked)}
                    className="w-4 h-4 rounded border-gray-300 dark:border-dark-border accent-green-600"
                  />
                  Coordinate Grid
                </label>
                <label className="flex items-center gap-2 cursor-pointer text-sm text-gray-700 dark:text-dark-text">
                  <input
                    type="checkbox"
                    checked={measurementMode}
                    onChange={(e) => setMeasurementMode(e.target.checked)}
                    className="w-4 h-4 rounded border-gray-300 dark:border-dark-border accent-orange-600"
                  />
                  Distance Measurement
                </label>
                {measurementMode && (
                  <p className="text-xs text-gray-400 dark:text-dark-muted pl-6">
                    Click to add points. Right-click to finish.
                  </p>
                )}
                <label className="flex items-center gap-2 cursor-pointer text-sm text-gray-700 dark:text-dark-text">
                  <input
                    type="checkbox"
                    checked={showElevationInfo}
                    onChange={(e) => setShowElevationInfo(e.target.checked)}
                    className="w-4 h-4 rounded border-gray-300 dark:border-dark-border accent-amber-600"
                  />
                  Cursor Elevation
                </label>
                <label className="flex items-center gap-2 cursor-pointer text-sm text-gray-700 dark:text-dark-text">
                  <input
                    type="checkbox"
                    checked={showElevationOverlay}
                    onChange={(e) => setShowElevationOverlay(e.target.checked)}
                    className="w-4 h-4 rounded border-gray-300 dark:border-dark-border accent-amber-600"
                  />
                  Elevation Colors
                </label>
              </div>
            </div>

            {/* Coverage statistics */}
            <CoverageStats
              points={coverageResult?.points ?? []}
              resolution={settings.resolution}
            />

            {/* Export coverage data */}
            <ExportPanel />

            {/* Site import/export */}
            <SiteImportExport />

            {/* Projects save/load */}
            <ProjectPanel />
          </div>
        </div>
      </div>

      <ToastContainer />
    </div>
  );
}
