'use client';

import { useState, useRef, useEffect, useCallback } from 'react';
import { useRouter } from 'next/navigation';
import type * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { boundaryApi } from '@/lib/api';
import type { GeoJSONFeatureCollection } from '@/lib/api';
import '../workstation-detail.css';
import './gis-viewer.css';

type LayerId = 'properties' | 'boundaries' | 'surveys' | 'disputes';

const LAYERS: { id: LayerId; name: string; icon: string }[] = [
  { id: 'properties', name: 'Properties', icon: '🏠' },
  { id: 'boundaries', name: 'Boundaries', icon: '🗺️' },
  { id: 'surveys', name: 'Survey Plans', icon: '📐' },
  { id: 'disputes', name: 'Disputes', icon: '⚖️' },
];

const NIGERIA_CENTER: [number, number] = [9.0820, 8.6753];
const DEFAULT_ZOOM = 6;

export default function GISViewerWorkstation() {
  const router = useRouter();
  const mapContainerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<L.Map | null>(null);
  const layersRef = useRef<Record<LayerId, L.GeoJSON | null>>({
    properties: null,
    boundaries: null,
    surveys: null,
    disputes: null,
  });
  const [layerVisibility, setLayerVisibility] = useState<Record<LayerId, boolean>>({
    properties: true,
    boundaries: true,
    surveys: false,
    disputes: false,
  });
  const [mapLoaded, setMapLoaded] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [selectedInfo, setSelectedInfo] = useState<Record<string, unknown> | null>(null);
  const [loadError, setLoadError] = useState<string | null>(null);

  const initMap = useCallback(async () => {
    if (!mapContainerRef.current || mapRef.current) return;
    const L = (await import('leaflet')).default;
    // Fix default icon path when using bundler (Next.js)
    delete (L.Icon.Default.prototype as unknown as { _getIconUrl?: unknown })._getIconUrl;
    L.Icon.Default.mergeOptions({
      iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
      iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
      shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
    });
    const map = L.map(mapContainerRef.current, {
      center: NIGERIA_CENTER,
      zoom: DEFAULT_ZOOM,
    });
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
    }).addTo(map);
    mapRef.current = map;
    setMapLoaded(true);
  }, []);

  const addGeoJsonLayer = useCallback(
    async (layerId: LayerId, geoJson: GeoJSONFeatureCollection, style: L.PathOptions & { radius?: number }) => {
      if (!mapRef.current || !geoJson.features?.length) return;
      const Leaflet = (await import('leaflet')).default;
      const { radius = 8, ...pathStyle } = style;
      const layer = Leaflet.geoJSON(geoJson as GeoJSON.GeoJSON, {
        style: (feature) => {
          const geom = feature?.geometry?.type;
          return geom === 'Point' ? {} : pathStyle;
        },
        pointToLayer: (_feature, latlng) => {
          return Leaflet.circleMarker(latlng, {
            radius: style.radius ?? 8,
            fillColor: (style as L.CircleMarkerOptions).fillColor ?? '#22c55e',
            color: (style as L.CircleMarkerOptions).color ?? '#16a34a',
            weight: 2,
            fillOpacity: (style as L.CircleMarkerOptions).fillOpacity ?? 0.6,
          });
        },
        onEachFeature(feature, layerInstance) {
          const props = (feature.properties || {}) as Record<string, unknown>;
          layerInstance.bindPopup(() => {
            const div = document.createElement('div');
            div.innerHTML = Object.entries(props)
              .map(([k, v]) => `<strong>${k}:</strong> ${v}`)
              .join('<br/>');
            return div;
          });
          layerInstance.on('click', () => setSelectedInfo(props));
        },
      });
      if (layerVisibility[layerId]) layer.addTo(mapRef.current!);
      layersRef.current[layerId] = layer;
    },
    [layerVisibility]
  );

  useEffect(() => {
    initMap();
    return () => {
      mapRef.current?.remove();
      mapRef.current = null;
      Object.keys(layersRef.current).forEach((k) => {
        layersRef.current[k as LayerId]?.remove();
        layersRef.current[k as LayerId] = null;
      });
    };
  }, [initMap]);

  useEffect(() => {
    if (!mapRef.current || !mapLoaded) return;
    const loadLayers = async () => {
      setLoadError(null);
      try {
        const [boundaries, properties, surveyPlans] = await Promise.all([
          boundaryApi.fetchBoundariesGeoJSON().catch(() => ({ type: 'FeatureCollection' as const, features: [] })),
          boundaryApi.fetchPropertiesGeoJSON().catch(() => ({ type: 'FeatureCollection' as const, features: [] })),
          boundaryApi.fetchSurveyPlansGeoJSON().catch(() => ({ type: 'FeatureCollection' as const, features: [] })),
        ]);
        const L = (await import('leaflet')).default;
        layersRef.current.boundaries?.remove();
        layersRef.current.properties?.remove();
        layersRef.current.surveys?.remove();
        if (boundaries.features.length) {
          await addGeoJsonLayer(
            'boundaries',
            boundaries,
            { color: '#2563eb', weight: 3 }
          );
        }
        if (properties.features.length) {
          await addGeoJsonLayer(
            'properties',
            properties,
            { color: '#16a34a', fillColor: '#22c55e', fillOpacity: 0.6, radius: 8 }
          );
        }
        if (surveyPlans.features.length) {
          await addGeoJsonLayer(
            'surveys',
            surveyPlans,
            { color: '#ea580c', fillColor: '#f97316', fillOpacity: 0.7, radius: 6 }
          );
        }
        if (!boundaries.features.length && !properties.features.length && !surveyPlans.features.length) {
          setLoadError('No boundary or property data from API. Use Laravel backend or add data.');
        }
      } catch (e) {
        setLoadError(e instanceof Error ? e.message : 'Failed to load GIS data');
      }
    };
    loadLayers();
  }, [mapLoaded, addGeoJsonLayer]);

  const toggleLayer = (id: LayerId) => {
    const next = { ...layerVisibility, [id]: !layerVisibility[id] };
    setLayerVisibility(next);
    const layer = layersRef.current[id];
    if (!mapRef.current || !layer) return;
    if (next[id]) layer.addTo(mapRef.current);
    else layer.remove();
  };

  const zoomIn = () => mapRef.current?.zoomIn();
  const zoomOut = () => mapRef.current?.zoomOut();
  const fitWorld = () => mapRef.current?.fitWorld();

  const handleSearch = () => {
    const q = searchQuery.trim().toLowerCase();
    if (!q) return;
    const allLayers = [layersRef.current.properties, layersRef.current.boundaries, layersRef.current.surveys];
    for (const geo of allLayers) {
      if (!geo) continue;
      geo.eachLayer((layer: L.Layer) => {
        const f = (layer as L.GeoJSON & { feature?: GeoJSON.Feature }).feature;
        const props = (f?.properties || {}) as Record<string, unknown>;
        const match = Object.values(props).some((v) => String(v).toLowerCase().includes(q));
        if (!match) return;
        const circle = layer as L.CircleMarker;
        const poly = layer as L.Polyline;
        const latLng = circle.getLatLng?.() ?? poly.getBounds?.()?.getCenter();
        if (latLng && mapRef.current) {
          mapRef.current.panTo(latLng);
          mapRef.current.setZoom(Math.max(mapRef.current.getZoom(), 12));
          (layer as L.Marker).openPopup?.();
          setSelectedInfo(props);
        }
      });
    }
  };

  return (
    <div className="workstation-detail gis-workstation">
      <div className="workstation-header-bar">
        <div>
          <h1>🗺️ GIS Viewer</h1>
          <p>OpenStreetMap base · Boundaries, properties & survey plans (GeoJSON). QGIS-compatible.</p>
        </div>
        <button onClick={() => router.push('/workstation')} className="btn-secondary">
          ← Back to Workstations
        </button>
      </div>

      <div className="gis-container">
        <div className="gis-sidebar">
          <div className="gis-controls">
            <h3>Map Layers</h3>
            <div className="layer-list">
              {LAYERS.map((layer) => (
                <label key={layer.id} className="layer-item">
                  <input
                    type="checkbox"
                    checked={layerVisibility[layer.id]}
                    onChange={() => toggleLayer(layer.id)}
                  />
                  <span className="layer-icon">{layer.icon}</span>
                  <span>{layer.name}</span>
                </label>
              ))}
            </div>

            <div className="gis-tools">
              <h3>Tools</h3>
              <div className="tool-buttons">
                <button type="button" className="tool-btn" title="Zoom In" onClick={zoomIn}>🔍+</button>
                <button type="button" className="tool-btn" title="Zoom Out" onClick={zoomOut}>🔍−</button>
                <button type="button" className="tool-btn" title="Fit world" onClick={fitWorld}>🌐</button>
              </div>
            </div>

            <div className="gis-search">
              <h3>Search</h3>
              <input
                type="text"
                placeholder="Property number, boundary, owner..."
                className="gis-search-input"
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
              />
              <button type="button" className="btn-primary" style={{ width: '100%', marginTop: '8px' }} onClick={handleSearch}>
                Search
              </button>
            </div>
          </div>
        </div>

        <div className="gis-map-container">
          <div ref={mapContainerRef} className="gis-map" id="gis-map" />
          {!mapLoaded && (
            <div className="map-placeholder">
              <div className="map-placeholder-content">
                <div className="map-icon">🗺️</div>
                <h3>Loading map…</h3>
              </div>
            </div>
          )}
          {loadError && (
            <div className="gis-load-error">
              {loadError}
            </div>
          )}
          <div className="gis-info-panel">
            {selectedInfo ? (
              <div className="property-info">
                <h4>Selection</h4>
                {Object.entries(selectedInfo).map(([k, v]) => (
                  <p key={k}><strong>{k}:</strong> {String(v)}</p>
                ))}
                <button type="button" onClick={() => setSelectedInfo(null)} className="btn-sm">Close</button>
              </div>
            ) : (
              <div className="map-info">
                <p>Click a boundary, property or survey plan on the map to view details. Use layers and search to filter.</p>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
