(() => {
  const KEY = (window.OPENWEATHER_API_KEY || "").trim();

  // UI
  const cityLabel = document.getElementById("cityLabel");
  const searchInput = document.getElementById("searchInput");
  const searchBtn = document.getElementById("searchBtn");
  const locateBtn = document.getElementById("locateBtn");

  const infoCard = document.getElementById("infoCard");
  const tempMain = document.getElementById("tempMain");
  const unitMain = document.getElementById("unitMain");
  const wxIcon = document.getElementById("wxIcon");
  const feelsLike = document.getElementById("feelsLike");
  const precip = document.getElementById("precip");
  const wind = document.getElementById("wind");
  const humidity = document.getElementById("humidity");
  const clouds = document.getElementById("clouds");
  const pressure = document.getElementById("pressure");

  const rpDate = document.getElementById("rpDate");
  const eventsList = document.getElementById("eventsList");
  const toast = document.getElementById("toast");

  const timeSlider = document.getElementById("timeSlider");
  const timeTicks = document.getElementById("timeTicks");
  const tlPrev = document.getElementById("tlPrev");
  const tlNext = document.getElementById("tlNext");

  const forecastGrid = document.getElementById("forecastGrid");
  const tableSub = document.getElementById("tableSub");

  const tabAll = document.getElementById("tabAll");
  const tabAlerts = document.getElementById("tabAlerts");

  // Map
  let map, overlayLayer, cityMarker;

  const LAYERS = {
    temperature: "temp_new",
    precipitation: "precipitation_new",
    pressure: "pressure_new",
    wind: "wind_new",
    clouds: "clouds_new",
  };

  // State
  let ctrl = null;
  let currentPlace = { name: "London", lat: 51.5072, lon: -0.1276 };
  let units = "metric";
  let cachedForecastList = [];   // 3h forecast list
  let selectedIdx = 0;           // timeline selection
  let activeTab = "all";         // all | alerts

  // ---------- Helpers ----------
  const iconUrl = (code) => `https://openweathermap.org/img/wn/${code}@2x.png`;
  const fmt2 = (n) => (Number.isFinite(n) ? n.toFixed(2) : "—");
  const fmtTime = (unix) => new Date(unix * 1000).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
  const fmtDate = (unix) => new Date(unix * 1000).toLocaleString([], { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });

  function showToast(msg) {
    toast.textContent = msg;
    toast.hidden = false;
    clearTimeout(showToast._t);
    showToast._t = setTimeout(() => (toast.hidden = true), 2400);
  }

  async function fetchJSON(url, signal) {
    const res = await fetch(url, { signal });
    const data = await res.json().catch(() => null);
    if (!res.ok) {
      const m = data && (data.message || data.error) ? (data.message || data.error) : `Request failed (${res.status})`;
      throw new Error(m);
    }
    return data;
  }

  // ---------- OpenWeather endpoints ----------
  async function geocode(q, signal) {
    const url = `https://api.openweathermap.org/geo/1.0/direct?q=${encodeURIComponent(q)}&limit=1&appid=${encodeURIComponent(KEY)}`;
    const arr = await fetchJSON(url, signal);
    if (!Array.isArray(arr) || !arr.length) throw new Error("City not found. Try: London,GB");
    return arr[0]; // {lat, lon, name, country, state}
  }

  async function currentByCoord(lat, lon, signal) {
    const url = `https://api.openweathermap.org/data/2.5/weather?lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lon)}&units=${encodeURIComponent(units)}&appid=${encodeURIComponent(KEY)}`;
    return await fetchJSON(url, signal);
  }

  async function forecast5ByCoord(lat, lon, signal) {
    const url = `https://api.openweathermap.org/data/2.5/forecast?lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lon)}&units=${encodeURIComponent(units)}&appid=${encodeURIComponent(KEY)}`;
    return await fetchJSON(url, signal);
  }

  // Optional alerts (might fail on some keys/plans)
  async function oneCallAlerts(lat, lon, signal) {
    const url = `https://api.openweathermap.org/data/2.5/onecall?lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lon)}&exclude=minutely,hourly,daily&appid=${encodeURIComponent(KEY)}`;
    return await fetchJSON(url, signal);
  }

  function buildOverlay(layerKey) {
    const owm = LAYERS[layerKey] || LAYERS.temperature;
    return L.tileLayer(
      `https://tile.openweathermap.org/map/${owm}/{z}/{x}/{y}.png?appid=${encodeURIComponent(KEY)}`,
      { opacity: 0.85 }
    );
  }

  function setActivePill(layerKey) {
    document.querySelectorAll(".layerPill").forEach((b) => {
      b.setAttribute("aria-selected", String(b.dataset.layer === layerKey));
    });
  }

  function setOverlay(layerKey) {
    if (!map) return;
    const next = buildOverlay(layerKey);
    map.removeLayer(overlayLayer);
    overlayLayer = next.addTo(map);
    setActivePill(layerKey);
  }

  // ---------- Render: Info card ----------
  function renderInfo(wx) {
    const u = units === "imperial" ? "F" : "C";
    unitMain.textContent = u;

    const t = Math.round(wx?.main?.temp ?? NaN);
    tempMain.textContent = Number.isFinite(t) ? String(t) : "—";

    const fl = Math.round(wx?.main?.feels_like ?? NaN);
    feelsLike.textContent = Number.isFinite(fl) ? `${fl}°${u}` : "—";

    const rain = wx?.rain?.["1h"] ?? wx?.rain?.["3h"] ?? 0;
    const snow = wx?.snow?.["1h"] ?? wx?.snow?.["3h"] ?? 0;
    precip.textContent = `${fmt2((Number(rain) || 0) + (Number(snow) || 0))} mm`;

    const spd = wx?.wind?.speed;
    wind.textContent = (typeof spd === "number") ? `${fmt2(spd)} ${units === "imperial" ? "mph" : "m/s"}` : "—";

    const hum = wx?.main?.humidity;
    humidity.textContent = (typeof hum === "number") ? `${hum}%` : "—";

    const cl = wx?.clouds?.all;
    clouds.textContent = (typeof cl === "number") ? `${cl}%` : "—";

    const pr = wx?.main?.pressure;
    pressure.textContent = (typeof pr === "number") ? `${pr} hPa` : "—";

    const icon = wx?.weather?.[0]?.icon;
    if (icon) {
      wxIcon.src = iconUrl(icon);
      wxIcon.alt = wx?.weather?.[0]?.main || "Weather";
      wxIcon.hidden = false;
    } else {
      wxIcon.hidden = true;
      wxIcon.removeAttribute("src");
    }

    infoCard.hidden = false;
  }

  // ---------- Bottom “table” forecast ----------
  function buildForecastGrid(list6) {
    // list6: 6 forecast items (3-hour steps)
    forecastGrid.innerHTML = "";

    const times = list6.map(it => fmtTime(it.dt));
    const icons = list6.map(it => it?.weather?.[0]?.icon || "");
    const temps = list6.map(it => Math.round(it?.main?.temp ?? NaN));
    const pops  = list6.map(it => Math.round(((it?.pop ?? 0) * 100)));
    const hums  = list6.map(it => Math.round(it?.main?.humidity ?? NaN));

    const u = units === "imperial" ? "°F" : "°C";

    const makeRow = (label, cells, renderFn) => {
      const row = document.createElement("div");
      row.className = "fRow";

      const head = document.createElement("div");
      head.className = "fCell fHead";
      head.textContent = label;
      row.appendChild(head);

      for (let i = 0; i < 6; i++) {
        const cell = document.createElement("div");
        cell.className = "fCell";
        cell.appendChild(renderFn(cells[i], i));
        row.appendChild(cell);
      }
      forecastGrid.appendChild(row);
    };

    makeRow("Time", times, (v) => {
      const d = document.createElement("div");
      d.className = "fTime";
      d.textContent = v;
      return d;
    });

    makeRow("Weather", icons, (code) => {
      const wrap = document.createElement("div");
      wrap.style.display = "flex";
      wrap.style.alignItems = "center";
      wrap.style.gap = "8px";

      const img = document.createElement("img");
      img.className = "fIcon";
      if (code) img.src = iconUrl(code);
      img.alt = "";

      const small = document.createElement("div");
      small.className = "small";
      small.textContent = code ? "" : "—";

      wrap.appendChild(img);
      wrap.appendChild(small);
      return wrap;
    });

    makeRow("Precip prob", pops, (v) => {
      const d = document.createElement("div");
      d.className = "fValue";
      d.textContent = Number.isFinite(v) ? `${v}%` : "—";
      return d;
    });

    makeRow("Temp", temps, (v) => {
      const d = document.createElement("div");
      d.className = "fValue";
      d.textContent = Number.isFinite(v) ? `${v}${u}` : "—";
      return d;
    });

    makeRow("Humidity", hums, (v) => {
      const d = document.createElement("div");
      d.className = "fValue";
      d.textContent = Number.isFinite(v) ? `${v}%` : "—";
      return d;
    });
  }

  function buildTimelineTicks(list6) {
    timeTicks.innerHTML = "";
    list6.forEach((it, idx) => {
      const s = document.createElement("span");
      s.textContent = fmtTime(it.dt);
      s.style.opacity = idx === selectedIdx ? "1" : ".75";
      timeTicks.appendChild(s);
    });
  }

  function applySelectedForecastToMarker(list6) {
    const it = list6[selectedIdx];
    if (!it) return;

    // Update marker label (live forecast time)
    if (cityMarker) {
      const t = Math.round(it?.main?.temp ?? NaN);
      const u = units === "imperial" ? "°F" : "°C";
      const label = Number.isFinite(t) ? `${currentPlace.name} · ${t}${u}` : currentPlace.name;
      cityMarker.bindTooltip(label, { permanent: true, direction: "top", offset: [0, -6], opacity: 0.9 }).openTooltip();
    }

    tableSub.textContent = `Live (3-hour steps) · Selected: ${fmtDate(it.dt)}`;
  }

  // ---------- Right panel: “Trigger Events” (live from forecast) ----------
  function buildEventsFromForecast(list) {
    // Use next ~24h (8 entries) for events
    const next = (Array.isArray(list) ? list : []).slice(0, 8);
    const out = [];

    // Thresholds (feel free to tweak)
    const coldThresholdC = 15;               // like your screenshot
    const windStrong = 10;                   // m/s
    const popLikely = 60;                    // %

    for (const it of next) {
      const when = fmtDate(it.dt);
      const t = it?.main?.temp;
      const pop = Math.round(((it?.pop ?? 0) * 100));
      const wMain = it?.weather?.[0]?.main || "";
      const ws = it?.wind?.speed;

      if (units === "metric" && typeof t === "number" && t < coldThresholdC) {
        out.push({ type: "warn", title: `Temperature falls below ${coldThresholdC}°C`, meta: when });
      }

      if (typeof ws === "number" && ws >= windStrong) {
        out.push({ type: "warn", title: `Strong wind expected`, meta: `${when} · ${fmt2(ws)} m/s` });
      }

      if (pop >= popLikely || ["Rain", "Snow", "Thunderstorm"].includes(wMain)) {
        out.push({ type: "info", title: `${wMain || "Precipitation"} likely`, meta: `${when} · ${pop}%` });
      }

      const hum = it?.main?.humidity;
      if (typeof hum === "number" && hum >= 90) {
        out.push({ type: "info", title: `Very high humidity`, meta: `${when} · ${hum}%` });
      }
    }

    // de-dupe similar events (simple)
    const uniq = [];
    const seen = new Set();
    for (const e of out) {
      const k = e.title + "|" + e.meta;
      if (!seen.has(k)) { seen.add(k); uniq.push(e); }
    }

    return uniq.slice(0, 8);
  }

  function renderEvents(events) {
    eventsList.innerHTML = "";
    if (!events.length) {
      eventsList.innerHTML = `<div class="event muted">No notable triggers in the next hours.</div>`;
      return;
    }

    for (const e of events) {
      const el = document.createElement("div");
      el.className = "event";

      const badgeClass = e.type === "danger" ? "badge bDanger" : e.type === "warn" ? "badge bWarn" : "badge bInfo";
      const badgeTxt = e.type === "danger" ? "Alert" : e.type === "warn" ? "Trigger" : "Info";

      el.innerHTML = `
        <div class="eventTitle"><span class="${badgeClass}">${badgeTxt}</span>${e.title}</div>
        <div class="eventMeta">${e.meta}</div>
      `;
      eventsList.appendChild(el);
    }
  }

  function setTab(which) {
    activeTab = which;
    tabAll.classList.toggle("active", which === "all");
    tabAlerts.classList.toggle("active", which === "alerts");

    // Re-render based on tab
    if (which === "alerts") {
      // alerts list is stored on last load if available
      renderEvents(window.__alertsEvents || []);
    } else {
      renderEvents(window.__forecastEvents || []);
    }
  }

  // ---------- Load city (live) ----------
  async function loadCity(queryOrPlace) {
    if (!KEY) {
      showToast("Missing API key. Create config.js from config.example.js");
      return;
    }

    if (ctrl) ctrl.abort();
    ctrl = new AbortController();

    try {
      showToast("Loading…");

      let place = null;
      if (typeof queryOrPlace === "string") {
        const g = await geocode(queryOrPlace, ctrl.signal);
        place = { name: g.name, lat: g.lat, lon: g.lon };
      } else {
        place = queryOrPlace; // {name,lat,lon}
      }

      currentPlace = place;
      cityLabel.textContent = place.name;

      map.setView([place.lat, place.lon], 7);

      // Current weather (for info card)
      const wx = await currentByCoord(place.lat, place.lon, ctrl.signal);
      renderInfo(wx);

      // Marker with temp label
      const u = units === "imperial" ? "°F" : "°C";
      const t = Math.round(wx?.main?.temp ?? NaN);
      const label = Number.isFinite(t) ? `${place.name} · ${t}${u}` : place.name;

      if (cityMarker) map.removeLayer(cityMarker);
      cityMarker = L.marker([place.lat, place.lon]).addTo(map);
      cityMarker.bindTooltip(label, { permanent: true, direction: "top", offset: [0, -6], opacity: 0.9 }).openTooltip();

      // Forecast (bottom + timeline + events)
      const fc = await forecast5ByCoord(place.lat, place.lon, ctrl.signal);
      cachedForecastList = Array.isArray(fc?.list) ? fc.list : [];

      const list6 = cachedForecastList.slice(0, 6);
      selectedIdx = 0;

      timeSlider.min = "0";
      timeSlider.max = String(Math.max(0, list6.length - 1));
      timeSlider.value = "0";

      buildForecastGrid(list6);
      buildTimelineTicks(list6);
      applySelectedForecastToMarker(list6);

      // Right panel date
      rpDate.textContent = new Date().toLocaleDateString(undefined, { day: "2-digit", month: "long", year: "numeric" });

      // Events from forecast (always works)
      window.__forecastEvents = buildEventsFromForecast(cachedForecastList);
      if (activeTab === "all") renderEvents(window.__forecastEvents);

      // Optional alerts (if supported)
      try {
        const oc = await oneCallAlerts(place.lat, place.lon, ctrl.signal);
        const alerts = Array.isArray(oc?.alerts) ? oc.alerts : [];
        window.__alertsEvents = alerts.slice(0, 6).map(a => ({
          type: "danger",
          title: a.event || "Weather Alert",
          meta: `${a.sender_name ? a.sender_name + " · " : ""}${a.start ? fmtDate(a.start) : ""}`
        }));
        if (activeTab === "alerts") renderEvents(window.__alertsEvents);
      } catch {
        window.__alertsEvents = [];
        if (activeTab === "alerts") renderEvents([]);
      }

      showToast(`Loaded: ${place.name}`);
      infoCard.hidden = false;
    } catch (err) {
      showToast(err?.message ? `Error: ${err.message}` : "Error loading city");
    }
  }

  // ---------- Map init ----------
  function initMap() {
    map = L.map("map", { zoomControl: true }).setView([51.5072, -0.1276], 6);

    // Dark base map (closest look)
    L.tileLayer("https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", {
      maxZoom: 19,
      attribution: "&copy; OpenStreetMap & CARTO"
    }).addTo(map);

    overlayLayer = buildOverlay("temperature").addTo(map);

    // Click on map => live current weather for that point
    map.on("click", async (e) => {
      if (!KEY) return;
      try {
        const wx = await currentByCoord(e.latlng.lat, e.latlng.lng);
        renderInfo(wx);
        showToast("Updated from map click");
      } catch {
        showToast("Could not load weather for that point");
      }
    });
  }

  // ---------- Location button ----------
  function useMyLocation() {
    if (!navigator.geolocation) return showToast("Geolocation not supported");
    navigator.geolocation.getCurrentPosition(
      async (pos) => {
        const { latitude, longitude } = pos.coords;
        map.setView([latitude, longitude], 8);
        await loadCity({ name: "My Location", lat: latitude, lon: longitude });
      },
      () => showToast("Location permission denied"),
      { enableHighAccuracy: true, timeout: 8000 }
    );
  }

  // ---------- Timeline handlers ----------
  function updateSelected(idx) {
    const list6 = cachedForecastList.slice(0, 6);
    selectedIdx = Math.max(0, Math.min(idx, list6.length - 1));
    timeSlider.value = String(selectedIdx);
    buildTimelineTicks(list6);
    applySelectedForecastToMarker(list6);
  }

  // ---------- Bind UI ----------
  function bindUI() {
    // layers
    document.querySelectorAll(".layerPill").forEach((b) => {
      b.addEventListener("click", () => setOverlay(b.dataset.layer));
    });

    // search
    searchBtn.addEventListener("click", () => {
      const q = searchInput.value.trim();
      if (q) loadCity(q);
    });
    searchInput.addEventListener("keydown", (e) => {
      if (e.key === "Enter") {
        const q = searchInput.value.trim();
        if (q) loadCity(q);
      }
    });

    // locate
    locateBtn.addEventListener("click", useMyLocation);

    // timeline
    timeSlider.addEventListener("input", () => updateSelected(parseInt(timeSlider.value, 10)));
    tlPrev.addEventListener("click", () => updateSelected(selectedIdx - 1));
    tlNext.addEventListener("click", () => updateSelected(selectedIdx + 1));

    // tabs
    tabAll.addEventListener("click", () => setTab("all"));
    tabAlerts.addEventListener("click", () => setTab("alerts"));
  }

  // ---------- Boot ----------
  initMap();
  bindUI();
  setActivePill("temperature");
  loadCity("London");
})();
