// ============ Continental LiveTracking — main app (live SignalR data) ============
const { useState: uS, useEffect: uE, useRef: uR, useMemo: uM } = React;

// ---- Map controller ----
function useLeafletMap(route, onReady) {
  const mapRef = uR(null);
  const truckRef = uR(null);
  const trailRef = uR(null);
  const routeRef = uR(null);

  uE(() => {
    if (mapRef.current) return;

    const map = L.map("map", {
      zoomControl: false,
      attributionControl: true,
      preferCanvas: true,
      zoomSnap: 0.25,
    });
    mapRef.current = map;

    // Esri satellite + Carto labels (no API key)
    L.tileLayer(
      "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
      { maxZoom: 19, attribution: 'Imagery &copy; Esri, Maxar, Earthstar Geographics' }
    ).addTo(map);
    L.tileLayer(
      "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png",
      { maxZoom: 19, attribution: '&copy; CARTO', subdomains: "abcd", opacity: 0.85 }
    ).addTo(map);

    // Track-outline as a static reference overlay (so the map has context before
    // the first GPS fix arrives). Driving doesn't follow this line any more.
    if (route && Array.isArray(route.pts) && route.pts.length > 1) {
      const fullLatLngs = route.pts.map((p) => L.latLng(p[0], p[1]));
      routeRef.current = L.polyline(fullLatLngs, {
        color: "#ffa500", weight: 4, opacity: 0.35, lineCap: "round",
        lineJoin: "round", dashArray: "1 8",
      }).addTo(map);
      map.fitBounds(routeRef.current.getBounds(), { padding: [80, 80], maxZoom: 17 });
    } else {
      map.setView([50.7374, 7.0982], 14);
    }

    // Trail polyline — gets points appended on every light snapshot.
    trailRef.current = L.polyline([], {
      color: "#ffa500", weight: 6, opacity: 1, lineCap: "round", lineJoin: "round",
    }).addTo(map);

    // Truck marker — only added the moment we get the first real position.
    const truckIcon = L.divIcon({
      className: "",
      html: `<div class="truck-marker"><div class="pulse"></div><div class="core">${window.TRUCK_MARKER_SVG || ""}</div></div>`,
      iconSize: [44, 44],
      iconAnchor: [22, 22],
    });
    truckRef.current = L.marker([0, 0], { icon: truckIcon, zIndexOffset: 1000, opacity: 0 }).addTo(map);

    setTimeout(() => onReady && onReady(), 350);

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

  return { mapRef, truckRef, trailRef };
}

// ---- Main App ----
function App() {
  const route = uM(() => {
    // route.js sets window.ROUTE = [[lat,lon], …] — used only as a static reference now.
    const pts = Array.isArray(window.ROUTE) ? window.ROUTE : [];
    return { pts };
  }, []);
  const meta = {
    vehicle: (window.PAGE_META && window.PAGE_META.vehicle) || "Mercedes Actros",
    tire: (window.PAGE_META && window.PAGE_META.tire) || "Conti EcoPlus HS3+",
    trackName: (window.PAGE_META && window.PAGE_META.trackName) || "High-Speed Oval",
    location: (window.PAGE_META && window.PAGE_META.location) || "Contidrom · Jeversen",
  };

  const [tweaks, setTweak] = window.useTweaks({ follow: true });
  const [mapReady, setMapReady] = uS(false);
  const { mapRef, truckRef, trailRef } = useLeafletMap(route, () => setMapReady(true));

  // Telemetry state, ticked by SignalR callbacks
  const [tick, setTick] = uS({
    speed: 0,            // km/h  (from light)
    heading: 0,          // deg
    lat: null, lon: null,
    source: "none",
    avgCons: 0,          // L/100km (from consumption)
    instCons: 0,         // L/100km
    totalCons: 0,        // L
    distM: 0,            // m
    durS: 0,             // s
    phase: "idle",       // consumption phase
    runCount: 0,
    hasConsumption: false,
  });
  const [consHistory, setConsHistory] = uS([]);
  const consHistRef = uR(0);

  // Connection state
  const [connState, setConnState] = uS("disconnected");
  const [connError, setConnError] = uS(null);

  // Track when we got the first GPS fix so we don't pan to (0,0)
  const hasFixRef = uR(false);
  const followRef = uR(tweaks.follow);
  uE(() => { followRef.current = tweaks.follow; }, [tweaks.follow]);

  // SignalR client lifecycle
  uE(() => {
    if (!mapReady) return;
    if (!window.PAGE_META || !window.PAGE_META.hubUrl) {
      setConnState("failed");
      setConnError("No hubUrl in PAGE_META — check appsettings.json");
      return;
    }
    if (!window.LiveDataClient) {
      setConnState("failed");
      setConnError("LiveDataClient not loaded");
      return;
    }

    const client = new window.LiveDataClient({
      hubUrl: window.PAGE_META.hubUrl,
      accessToken: window.PAGE_META.accessToken,
      senderId: window.PAGE_META.senderId,
      onStateChange: (s, info) => {
        setConnState(s);
        if (info && info.message) setConnError(info.message);
        else if (s === "connected") setConnError(null);
      },
      onLight: (p) => {
        const lat = Number(p.lat);
        const lon = Number(p.lon);
        const speed = Number(p.speed_kmh ?? 0);
        const heading = Number(p.heading_deg ?? 0);
        const source = p.source || "none";

        setTick((t) => ({ ...t, speed, heading, lat, lon, source }));

        if (Number.isFinite(lat) && Number.isFinite(lon)
            && (Math.abs(lat) > 0.000001 || Math.abs(lon) > 0.000001)) {
          if (truckRef.current) {
            truckRef.current.setLatLng([lat, lon]);
            truckRef.current.setOpacity(1);
          }
          if (trailRef.current) {
            trailRef.current.addLatLng(L.latLng(lat, lon));
          }
          if (!hasFixRef.current) {
            hasFixRef.current = true;
            if (mapRef.current) mapRef.current.setView([lat, lon], 17);
          } else if (followRef.current && mapRef.current) {
            mapRef.current.panTo([lat, lon], { animate: true, duration: 0.3 });
          }
        }
      },
      onConsumption: (p) => {
        const inst = Number(p.instant_per_100km ?? 0);
        setTick((t) => ({
          ...t,
          hasConsumption: true,
          avgCons: Number(p.avg_per_100km ?? 0),
          instCons: inst,
          totalCons: Number(p.total_consumption ?? 0),
          distM: Number(p.distance_m ?? 0),
          durS: Number(p.duration_s ?? 0),
          phase: String(p.phase || "idle"),
          runCount: Number(p.run_count ?? 0),
        }));

        // ~1 sample/sec into consumption sparkline (regardless of stream rate)
        consHistRef.current = (consHistRef.current + 1) % 1;
        setConsHistory((h) => {
          const next = [...h, inst];
          return next.length > 60 ? next.slice(-60) : next;
        });
      }
    });

    client.start();

    return () => { client.stop(); };
  }, [mapReady]);

  // Map "follow" toggled on → re-centre on current truck position
  uE(() => {
    if (tweaks.follow && truckRef.current && mapRef.current && hasFixRef.current) {
      mapRef.current.panTo(truckRef.current.getLatLng());
    }
  }, [tweaks.follow]);

  // Wall-clock
  const [clock, setClock] = uS(() => new Date());
  uE(() => {
    const id = setInterval(() => setClock(new Date()), 1000);
    return () => clearInterval(id);
  }, []);

  const fmt = {
    int: (v) => Math.round(v).toString(),
    one: (v) => Number(v).toFixed(1),
    two: (v) => Number(v).toFixed(2),
    time: (s) => {
      s = Math.max(0, Math.floor(s));
      const h = Math.floor(s / 3600);
      const m = Math.floor((s % 3600) / 60);
      const ss = s % 60;
      return [h, m, ss].map((n) => String(n).padStart(2, "0")).join(":");
    },
  };

  const gear = tick.speed < 5 ? "N" : tick.speed < 15 ? "1" : tick.speed < 30 ? "2"
             : tick.speed < 50 ? "3" : tick.speed < 70 ? "4" : tick.speed < 85 ? "5" : "6";

  const connPillClass =
    connState === "connected" ? "live-pill live-pill-on" :
    (connState === "connecting" || connState === "reconnecting") ? "live-pill live-pill-busy" :
    "live-pill live-pill-off";
  const connPillLabel =
    connState === "connected" ? "Live" :
    connState === "connecting" ? "Connecting" :
    connState === "reconnecting" ? "Reconnecting" :
    connState === "failed" ? "Failed" :
    "Offline";

  return (
    <div className="app">
      <header className="header">
        <div className="brand">
          <img src="assets/continental-logo.png" alt="Continental" className="brand-logo"
               onError={(e) => { e.target.style.display = 'none'; }} />
        </div>

        <div className="event">
          <nav className="nav-tabs">
            <a className="nav-tab" href="/VehicleTracking"><span className="dot"></span>Vehicle Tracking</a>
            <a className="nav-tab active" href={(window.PAGE_META && window.PAGE_META.liveUrl) || "/"}><span className="dot"></span>Consumption Test</a>
            <a className="nav-tab" href={(window.PAGE_META && window.PAGE_META.brakingUrl) || "/Braking"}><span className="dot"></span>Braking Tests</a>
            <a className="nav-tab" href={(window.PAGE_META && window.PAGE_META.diagnosticUrl) || "/Diagnostic"}><span className="dot"></span>Diagnostic</a>
            <a className="nav-tab" href="/Settings"><span className="dot"></span>Settings</a>
            <a className="nav-tab" href="/Logout"><span className="dot"></span>Logout</a>
          </nav>
        </div>

        <div className="header-right">
          <span className={connPillClass} title={connError || ""}>
            <span className="live-dot"></span>
            {connPillLabel}
          </span>
          <span className="clock">
            <span className="label">CET</span>
            {clock.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit", second: "2-digit" })}
          </span>
        </div>
      </header>

      <div className="main">
        <div className="map-wrap">
          <div id="map"></div>

          <div className={`loading ${mapReady ? "gone" : ""}`}>
            <div className="spinner"></div>
            Loading map…
          </div>

          {/* Top-left status card */}
          <div className="map-overlay route-card">
            <div className="head">
              <h3>{meta.trackName}</h3>
              <span className="progress-pct">{tick.source.toUpperCase()}</span>
            </div>
            <div className="route-endpoints">
              <span className="pt start"><span className="dot"></span><strong>{meta.location}</strong></span>
              <span className="pt end">
                <strong>
                  {tick.lat != null && tick.lon != null
                    ? `${tick.lat.toFixed(5)} / ${tick.lon.toFixed(5)}`
                    : "Awaiting GPS fix"}
                </strong>
              </span>
            </div>
          </div>

          <div className="map-overlay map-controls">
            <label className="map-toggle">
              <input type="checkbox"
                     checked={tweaks.follow}
                     onChange={(e) => setTweak("follow", e.target.checked)} />
              <span className="map-toggle-label">Auto-center on truck</span>
            </label>
            <button type="button"
                    className="map-mini-btn"
                    onClick={() => {
                      if (truckRef.current && mapRef.current && hasFixRef.current) {
                        mapRef.current.setView(truckRef.current.getLatLng(), 17);
                      }
                    }}>
              Recenter now
            </button>
          </div>

          <div className="map-overlay map-legend">
            <span className="leg"><span className="swatch route"></span>Track outline</span>
            <span className="leg"><span className="swatch trail"></span>Live trail</span>
            <span className="leg"><span className="truck-dot"></span>Truck position</span>
          </div>
        </div>

        <aside className="rail">
          <div className="truck-hero">
            <div className="label"><span>Vehicle</span></div>
            <h2>{meta.vehicle}</h2>
            <div className="sub">{meta.tire}</div>
          </div>

          <div className="gauge-section">
            <div className="label"><span>Current Speed</span></div>
            <div className="gauge-wrap">
              <window.SpeedGauge value={tick.speed} max={120}/>
              <div className="gauge-readout">
                <div>
                  <div className="v">{fmt.int(tick.speed)}</div>
                  <div className="u">km / h</div>
                </div>
              </div>
            </div>
            <div className="tag-row">
              <span className="tag gear">Gear {gear}</span>
            </div>
          </div>

          <div className="stats">
            <div className="stat-card">
              <div className="label">
                <svg className="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2"><path d="M3 22h12V2H7v4H3z"/><path d="M15 8h3l3 3v11h-6"/></svg>
                Avg Consumption
              </div>
              <div>
                <span className="v">{tick.hasConsumption ? fmt.one(tick.avgCons) : "—"}</span>
                <span className="u"> L/100km</span>
              </div>
              <div className={`delta ${tick.instCons < tick.avgCons ? "good" : "bad"}`}>
                {tick.hasConsumption
                  ? `Now ${fmt.one(tick.instCons)} L/100km · ${tick.instCons < tick.avgCons ? "▼" : "▲"} ${Math.abs(tick.instCons - tick.avgCons).toFixed(1)}`
                  : "No active trip"}
              </div>
            </div>

            <div className="stat-card">
              <div className="label">
                <svg className="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 1 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
                Distance
              </div>
              <div>
                <span className="v">{tick.hasConsumption ? fmt.two(tick.distM / 1000) : "—"}</span>
                <span className="u"> km</span>
              </div>
              <div className="delta">
                {tick.hasConsumption
                  ? `Trip · phase ${tick.phase}`
                  : "—"}
              </div>
            </div>

            <div className="stat-card">
              <div className="label">
                <svg className="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
                Trip Time
              </div>
              <div>
                <span className="v">{tick.hasConsumption ? fmt.time(tick.durS) : "—"}</span>
                <span className="u"></span>
              </div>
              <div className="delta">
                {tick.hasConsumption ? `${tick.runCount} saved trips` : "No active trip"}
              </div>
            </div>

            <div className="stat-card">
              <div className="label">
                <svg className="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2"><path d="M3 22V8l6-4 6 4v14"/><path d="M14 8h4l3 3v11h-7"/></svg>
                Fuel Used
              </div>
              <div>
                <span className="v">{tick.hasConsumption ? fmt.one(tick.totalCons) : "—"}</span>
                <span className="u"> L</span>
              </div>
              <div className="delta">
                {tick.hasConsumption
                  ? `CO₂ ≈ ${(tick.totalCons * 2.64).toFixed(1)} kg`
                  : "—"}
              </div>
            </div>
          </div>

          <div className="spark-card">
            <div className="head">
              <span className="label">Consumption · last 60 samples</span>
              <span className="now">{tick.hasConsumption ? `${fmt.one(tick.instCons)} L/100km` : "—"}</span>
            </div>
            <window.Sparkline data={consHistory} min={14} max={38}/>
          </div>

          <div className="rail-footer">
            <span className={connState === "connected" ? "ok" : "err"}>
              {connState === "connected" ? "Telemetry stream healthy" : `Telemetry · ${connState}`}
            </span>
            <span>Sender {window.PAGE_META ? window.PAGE_META.senderId : "?"} · src {tick.source}</span>
          </div>
        </aside>
      </div>

      <window.TweaksPanel title="Map Controls">
        <window.TweakSection title="Camera">
          <window.TweakToggle
            label="Follow truck"
            value={tweaks.follow}
            onChange={(v) => setTweak("follow", v)}
          />
        </window.TweakSection>
      </window.TweaksPanel>
    </div>
  );
}

window.App = App;
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
