"use client";

import { useEffect, useRef, useState, useCallback } from "react";
import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import { PALETTES, DEFAULT_PALETTE } from "@/lib/palettes";

interface MapViewProps {
  /** GeoJSON FeatureCollection to display */
  geojson: GeoJSON.FeatureCollection | null;
  /** Property key to use for choropleth coloring */
  colorProperty?: string;
  /** Label for the color property (for legend) */
  colorLabel?: string;
  /** Variables to show in tooltip */
  displayVariables?: Array<{ key: string; label: string }>;
  /** Temporal series metadata for sparkline charts */
  temporalSeries?: { baseVar: string; years: string[] } | null;
  /** Called when a feature is clicked */
  onFeatureClick?: (properties: Record<string, unknown>) => void;
  /** Active palette ID (controlled from parent) */
  paletteId?: string;
  /** Called when palette changes */
  onPaletteChange?: (id: string) => void;
}

const BASEMAP_URL =
  "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json";

// Romania bounding box
const ROMANIA_BOUNDS: maplibregl.LngLatBoundsLike = [
  [20.2, 43.6],
  [30.0, 48.3],
];



export function MapView({
  geojson,
  colorProperty,
  colorLabel,
  displayVariables = [],
  temporalSeries,
  onFeatureClick,
  paletteId: controlledPaletteId,
  onPaletteChange,
}: MapViewProps) {
  const mapContainer = useRef<HTMLDivElement>(null);
  const map = useRef<maplibregl.Map | null>(null);
  const popup = useRef<maplibregl.Popup | null>(null);
  const [legendItems, setLegendItems] = useState<
    Array<{ color: string; label: string }>
  >([]);
  const [mapLoaded, setMapLoaded] = useState(false);
  const [internalPaletteId, setInternalPaletteId] = useState(DEFAULT_PALETTE);
  const paletteId = controlledPaletteId ?? internalPaletteId;
  const setPaletteId = (id: string) => {
    setInternalPaletteId(id);
    onPaletteChange?.(id);
  };
  const palette = PALETTES[paletteId] || PALETTES[DEFAULT_PALETTE];
  const COLOR_SCALE = palette.colors;

  // Initialize map
  useEffect(() => {
    if (!mapContainer.current || map.current) return;

    map.current = new maplibregl.Map({
      container: mapContainer.current,
      style: BASEMAP_URL,
      bounds: ROMANIA_BOUNDS,
      fitBoundsOptions: { padding: 40 },
      attributionControl: {},
    });

    map.current.addControl(
      new maplibregl.NavigationControl({ showCompass: false }),
      "top-right"
    );

    popup.current = new maplibregl.Popup({
      closeButton: false,
      closeOnClick: false,
      className: "map-tooltip",
      maxWidth: "300px",
    });

    map.current.on("load", () => {
      setMapLoaded(true);
    });

    return () => {
      if (map.current) {
        map.current.remove();
        map.current = null;
      }
    };
  }, []);

  // Update data layer
  useEffect(() => {
    if (!map.current || !mapLoaded) return;

    const sourceId = "data-source";
    const layerId = "data-fill";
    const outlineLayerId = "data-outline";

    // Remove existing layers/source
    if (map.current.getLayer(outlineLayerId)) {
      map.current.removeLayer(outlineLayerId);
    }
    if (map.current.getLayer(layerId)) {
      map.current.removeLayer(layerId);
    }
    if (map.current.getSource(sourceId)) {
      map.current.removeSource(sourceId);
    }

    if (!geojson || geojson.features.length === 0) {
      setLegendItems([]);
      return;
    }

    // Add source
    map.current.addSource(sourceId, {
      type: "geojson",
      data: geojson,
    });

    // Build color expression
    let paintFill: maplibregl.FillLayerSpecification["paint"] = {
      "fill-color": "rgba(6, 182, 212, 0.3)",
      "fill-opacity": 0.7,
    };

    if (colorProperty) {
      // Calculate quantile breaks for choropleth
      const values = geojson.features
        .map((f) => {
          const val = f.properties?.[colorProperty];
          if (typeof val === "string") {
            // Handle European formats like "1.234,56" or "-" or "" gracefully
            const clean = val.replace(/\s/g, "").replace(",", ".");
            return parseFloat(clean);
          }
          return val;
        })
        .filter((v): v is number => typeof v === "number" && !isNaN(v))
        .sort((a, b) => a - b);

      if (values.length > 0) {
        const numClasses = Math.min(COLOR_SCALE.length, values.length);
        const breaks: number[] = [];

        for (let i = 1; i < numClasses; i++) {
          const idx = Math.floor((i / numClasses) * values.length);
          breaks.push(values[idx]);
        }

        // Build MapLibre step expression
        const stepExpr: unknown[] = [
          "step",
          ["to-number", ["get", colorProperty], 0],
          COLOR_SCALE[0],
        ];

        for (let i = 0; i < breaks.length; i++) {
          stepExpr.push(breaks[i], COLOR_SCALE[i + 1]);
        }

        paintFill = {
          "fill-color": stepExpr as maplibregl.ExpressionSpecification,
          "fill-opacity": [
            "case",
            ["boolean", ["feature-state", "hover"], false],
            0.9,
            0.7,
          ],
        };

        // Build legend
        const items: Array<{ color: string; label: string }> = [];
        const fmt = (n: number) =>
          n >= 1000000
            ? `${(n / 1000000).toFixed(1)}M`
            : n >= 1000
              ? `${(n / 1000).toFixed(1)}K`
              : String(Math.round(n));

        items.push({
          color: COLOR_SCALE[0],
          label: `< ${fmt(breaks[0])}`,
        });
        for (let i = 0; i < breaks.length - 1; i++) {
          items.push({
            color: COLOR_SCALE[i + 1],
            label: `${fmt(breaks[i])} — ${fmt(breaks[i + 1])}`,
          });
        }
        items.push({
          color: COLOR_SCALE[breaks.length],
          label: `> ${fmt(breaks[breaks.length - 1])}`,
        });

        setLegendItems(items);
      }
    } else {
      setLegendItems([]);
    }

    // Add fill layer
    map.current.addLayer({
      id: layerId,
      type: "fill",
      source: sourceId,
      paint: paintFill,
    });

    // Add outline layer
    map.current.addLayer({
      id: outlineLayerId,
      type: "line",
      source: sourceId,
      paint: {
        "line-color": palette.outline,
        "line-width": [
          "case",
          ["boolean", ["feature-state", "hover"], false],
          2.5,
          1,
        ],
      },
    });

    // Tooltip on hover
    let hoveredId: string | number | undefined;

    map.current.on("mousemove", layerId, (e) => {
      if (!map.current || !e.features || e.features.length === 0) return;

      map.current.getCanvas().style.cursor = "pointer";
      const feature = e.features[0];
      const props = feature.properties || {};

      // Build tooltip HTML
      const name =
        props.name || props.Name || props.NAME || props.natcode || "";
      let html = `<div class="map-tooltip__title">${name}</div>`;

      // Sparkline chart for temporal series — shown at top
      if (temporalSeries && temporalSeries.years.length > 1) {
        const ts = temporalSeries;
        const dataPoints: { year: string; value: number }[] = [];
        for (const yr of ts.years) {
          const key = `${ts.baseVar}_${yr}`;
          const raw = props[key];
          let num: number | null = null;
          if (typeof raw === 'number' && !isNaN(raw)) num = raw;
          else if (typeof raw === 'string') {
            const clean = raw.replace(/\s/g, '').replace(',', '.');
            const parsed = parseFloat(clean);
            if (!isNaN(parsed)) num = parsed;
          }
          if (num !== null) dataPoints.push({ year: yr, value: num });
        }

        if (dataPoints.length > 1) {
          const vals = dataPoints.map(d => d.value);
          const minV = Math.min(...vals);
          const maxV = Math.max(...vals);
          const range = maxV - minV || 1;
          const W = 240, H = 60, PX = 4, PY = 6;
          const stepX = (W - 2 * PX) / (dataPoints.length - 1);

          const points = dataPoints.map((d, i) => {
            const x = PX + i * stepX;
            const y = PY + (1 - (d.value - minV) / range) * (H - 2 * PY);
            return `${x},${y}`;
          }).join(' ');

          const areaPoints = `${PX},${H - PY} ` + dataPoints.map((d, i) => {
            const x = PX + i * stepX;
            const y = PY + (1 - (d.value - minV) / range) * (H - 2 * PY);
            return `${x},${y}`;
          }).join(' ') + ` ${PX + (dataPoints.length - 1) * stepX},${H - PY}`;

          const currentYearSuffix = colorProperty ? colorProperty.split('_').pop() : '';
          const highlightIdx = dataPoints.findIndex(d => d.year === currentYearSuffix);
          const firstYear = dataPoints[0].year;
          const lastYear = dataPoints[dataPoints.length - 1].year;
          const fmtV = (n: number) => n >= 1000000 ? `${(n/1000000).toFixed(1)}M` : n >= 1000 ? `${(n/1000).toFixed(1)}K` : String(Math.round(n));

          // Current year value label
          let currentLabel = '';
          if (highlightIdx >= 0) {
            currentLabel = `<span style="font-size:10px;color:white;font-weight:600;float:right">${fmtV(dataPoints[highlightIdx].value)} (${dataPoints[highlightIdx].year})</span>`;
          }

          let svg = `<div style="margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid rgba(255,255,255,0.1)">`;
          svg += `<div style="font-size:10px;color:rgba(255,255,255,0.5);margin-bottom:3px">${colorLabel || ts.baseVar} ${currentLabel}</div>`;
          svg += `<svg width="${W}" height="${H + 16}" viewBox="0 0 ${W} ${H + 16}" style="display:block">`;
          svg += `<defs><linearGradient id="sparkArea" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="${palette.colors[3]}" stop-opacity="0.3"/><stop offset="100%" stop-color="${palette.colors[3]}" stop-opacity="0.02"/></linearGradient></defs>`;
          svg += `<polygon points="${areaPoints}" fill="url(#sparkArea)"/>`;
          svg += `<polyline points="${points}" fill="none" stroke="${palette.colors[3]}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`;
          if (highlightIdx >= 0) {
            const hx = PX + highlightIdx * stepX;
            const hy = PY + (1 - (dataPoints[highlightIdx].value - minV) / range) * (H - 2 * PY);
            svg += `<circle cx="${hx}" cy="${hy}" r="4" fill="white" stroke="${palette.colors[4]}" stroke-width="2"/>`;
          }
          svg += `<text x="${PX}" y="${H + 12}" fill="rgba(255,255,255,0.4)" font-size="9" font-family="Inter,sans-serif">${firstYear}</text>`;
          svg += `<text x="${W - PX}" y="${H + 12}" fill="rgba(255,255,255,0.4)" font-size="9" font-family="Inter,sans-serif" text-anchor="end">${lastYear}</text>`;
          svg += `<text x="${W - PX}" y="${PY + 3}" fill="rgba(255,255,255,0.35)" font-size="8" font-family="Inter,sans-serif" text-anchor="end">${fmtV(maxV)}</text>`;
          svg += `<text x="${W - PX}" y="${H - PY + 3}" fill="rgba(255,255,255,0.35)" font-size="8" font-family="Inter,sans-serif" text-anchor="end">${fmtV(minV)}</text>`;
          svg += `</svg></div>`;
          html += svg;
        }
      }

      // Variable list — truncated to MAX_TOOLTIP_ROWS
      const MAX_TOOLTIP_ROWS = 6;
      if (displayVariables && displayVariables.length > 0) {
        // Always ensure the active color variable is visible
        const activeVar = displayVariables.find(v => v.key === colorProperty);
        const otherVars = displayVariables.filter(v => v.key !== colorProperty && props[v.key] !== undefined);
        const visibleVars: typeof displayVariables = [];

        // Active variable first
        if (activeVar && props[activeVar.key] !== undefined) {
          visibleVars.push(activeVar);
        }
        // Fill remaining slots
        for (const v of otherVars) {
          if (visibleVars.length >= MAX_TOOLTIP_ROWS) break;
          visibleVars.push(v);
        }
        const hiddenCount = otherVars.length - (visibleVars.length - (activeVar && props[activeVar.key] !== undefined ? 1 : 0));

        visibleVars.forEach((v) => {
          const val =
            typeof props[v.key] === "number"
              ? props[v.key].toLocaleString("ro-RO")
              : props[v.key];
          const isColorKey = colorProperty === v.key;
          html += `<div class="map-tooltip__row ${isColorKey ? 'map-tooltip__row--active' : ''}" style="${isColorKey ? 'font-weight: 600; color: var(--color-primary);' : ''}">
            <span class="map-tooltip__label">${v.label}</span>
            <span class="map-tooltip__value">${val}</span>
          </div>`;
        });

        if (hiddenCount > 0) {
          html += `<div style="font-size:10px;color:rgba(255,255,255,0.3);padding:3px 0;text-align:center">…și încă ${hiddenCount} variabile</div>`;
        }
      } else if (colorProperty && props[colorProperty] !== undefined) {
        const label = colorLabel || colorProperty;
        const val =
          typeof props[colorProperty] === "number"
            ? props[colorProperty].toLocaleString("ro-RO")
            : props[colorProperty];
        html += `<div class="map-tooltip__row">
          <span class="map-tooltip__label">${label}</span>
          <span class="map-tooltip__value">${val}</span>
        </div>`;
      }

      popup.current
        ?.setLngLat(e.lngLat)
        .setHTML(html)
        .addTo(map.current!);
    });

    map.current.on("mouseleave", layerId, () => {
      if (!map.current) return;
      map.current.getCanvas().style.cursor = "";
      popup.current?.remove();
    });

    // Click handler
    map.current.on("click", layerId, (e) => {
      if (e.features && e.features.length > 0 && onFeatureClick) {
        onFeatureClick(e.features[0].properties || {});
      }
    });

    // Fit map to data bounds
    const bounds = new maplibregl.LngLatBounds();
    geojson.features.forEach((feature) => {
      const addCoords = (coords: number[] | number[][] | number[][][]) => {
        if (typeof coords[0] === "number") {
          bounds.extend(coords as [number, number]);
        } else {
          (coords as (number[] | number[][])[]).forEach(addCoords);
        }
      };
      if (feature.geometry && "coordinates" in feature.geometry) {
        addCoords(feature.geometry.coordinates as number[]);
      }
    });

    if (!bounds.isEmpty()) {
      map.current.fitBounds(bounds, { padding: 60, duration: 800 });
    }
  }, [geojson, colorProperty, colorLabel, onFeatureClick, mapLoaded, paletteId, temporalSeries]);

  return (
    <div className="map-container">
      <div
        ref={mapContainer}
        style={{ width: "100%", height: "100%" }}
      />
      {legendItems.length > 0 && (
        <div className="map-legend">
          <div className="map-legend__title">
            {colorLabel || colorProperty}
          </div>
          <div className="map-legend__items">
            {legendItems.map((item, i) => (
              <div key={i} className="map-legend__item">
                <div
                  className="map-legend__color"
                  style={{ backgroundColor: item.color }}
                />
                <span>{item.label}</span>
              </div>
            ))}
          </div>
          {/* Palette selector */}
          <div style={{
            marginTop: 10, paddingTop: 8,
            borderTop: '1px solid var(--color-border)',
            display: 'flex', gap: 4, flexWrap: 'wrap',
          }}>
            {Object.entries(PALETTES).map(([id, p]) => (
              <button
                key={id}
                title={p.name}
                onClick={() => setPaletteId(id)}
                style={{
                  width: 28, height: 14,
                  borderRadius: 3, cursor: 'pointer',
                  border: id === paletteId ? '2px solid white' : '1px solid var(--color-border)',
                  background: `linear-gradient(90deg, ${p.colors[0]}, ${p.colors[2]}, ${p.colors[5]})`,
                  padding: 0,
                  boxShadow: id === paletteId ? '0 0 4px rgba(255,255,255,0.4)' : 'none',
                  transition: 'all 0.15s ease',
                }}
              />
            ))}
          </div>
        </div>
      )}

      {/* Empty state overlay */}
      {!geojson && (
        <div
          style={{
            position: "absolute",
            inset: 0,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            pointerEvents: "none",
          }}
        >
          <div
            style={{
              background: "var(--color-bg-glass)",
              backdropFilter: "blur(12px)",
              border: "1px solid var(--color-border)",
              borderRadius: "var(--radius-xl)",
              padding: "32px 48px",
              textAlign: "center",
            }}
          >
            <div
              style={{
                fontSize: 40,
                marginBottom: 12,
              }}
            >
              🗺️
            </div>
            <div
              style={{
                fontSize: 16,
                fontWeight: 600,
                color: "var(--color-text-primary)",
                marginBottom: 6,
              }}
            >
              Alegeți datele din panoul lateral
            </div>
            <div
              style={{
                fontSize: 13,
                color: "var(--color-text-muted)",
              }}
            >
              Selectați geometria, setul de date și coloanele,
              <br />
              apoi apăsați &ldquo;Previzualizare pe hartă&rdquo;
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
