/* WeatherMate — app root */

const DEFAULT_CITY = { id: "thunderbay", name: "Thunder Bay", admin: "Ontario", country: "Canada", lat: 48.3809, lon: -89.2477 };

const COND_BY_LABEL = { Clear: "clear", "Partly Cloudy": "partly", Cloudy: "cloudy", Fog: "fog", Rain: "rain", Snow: "snow", Thunderstorm: "thunder" };
const CODE_BY_COND = { clear: 0, partly: 2, cloudy: 3, fog: 45, drizzle: 53, rain: 63, snow: 73, thunder: 95 };

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "style": "classic",
  "units": "°C",
  "animations": true,
  "timeOfDay": "Auto",
  "forceWeather": "Auto"
}/*EDITMODE-END*/;

/* ---- pull to refresh hook (touch) ---- */
function usePullToRefresh(onRefresh) {
  const [height, setHeight] = React.useState(0);
  const [spinning, setSpinning] = React.useState(false);
  const startY = React.useRef(null);
  const hRef = React.useRef(0);
  const THRESH = 62;
  hRef.current = height;

  const bind = (scrollRef) => ({
    onTouchStart: (e) => {
      if (!spinning && scrollRef.current && scrollRef.current.scrollTop <= 0) startY.current = e.touches[0].clientY;
    },
    onTouchMove: (e) => {
      if (startY.current == null) return;
      const dy = e.touches[0].clientY - startY.current;
      if (dy > 0 && scrollRef.current && scrollRef.current.scrollTop <= 0) {
        setHeight(Math.min(96, dy * 0.5));
      } else if (dy <= 0) {
        setHeight(0);
      }
    },
    onTouchEnd: async () => {
      if (startY.current == null) return;
      startY.current = null;
      if (hRef.current >= THRESH && !spinning) {
        setSpinning(true); setHeight(54);
        try { await onRefresh(); } catch (e) {}
        setSpinning(false); setHeight(0);
      } else { setHeight(0); }
    },
  });
  return { height, spinning, bind, zoneRef: React.useRef(null) };
}

function Loader({ theme }) {
  return (
    <div className="screen" style={{ alignItems: "center", justifyContent: "center" }}>
      <div className="ptr-spinner spin" style={{ animation: "spin 0.7s linear infinite", width: 34, height: 34 }} />
      <div style={{ marginTop: 16, color: "rgba(255,255,255,0.7)", fontSize: 15, fontWeight: 600, letterSpacing: 0.3 }}>Fetching live weather…</div>
    </div>
  );
}

function UnitToggle({ unit, onToggle }) {
  return (
    <button className="glass" onClick={onToggle} style={{
      position: "absolute", top: 50, right: 16, zIndex: 6,
      display: "flex", borderRadius: 20, overflow: "hidden", padding: 3, gap: 2,
    }}>
      {["c", "f"].map(u => (
        <span key={u} style={{
          fontSize: 13, fontWeight: 700, padding: "4px 11px", borderRadius: 16,
          background: unit === u ? "rgba(255,255,255,0.85)" : "transparent",
          color: unit === u ? "#1a1330" : "rgba(255,255,255,0.8)",
          transition: "all 0.2s",
        }}>°{u.toUpperCase()}</span>
      ))}
    </button>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const unit = t.units === "°F" ? "f" : "c";

  const [saved, setSaved] = React.useState(() => {
    try { const s = JSON.parse(localStorage.getItem("wm_cities")); if (s && s.length) return s; } catch (e) {}
    return [DEFAULT_CITY];
  });
  const [activeId, setActiveId] = React.useState(() => {
    try { return localStorage.getItem("wm_active") || saved[0].id; } catch (e) { return saved[0].id; }
  });
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [sample, setSample] = React.useState(false);
  const [view, setView] = React.useState("home");
  const [forecastMode, setForecastMode] = React.useState("hourly");
  const [clock, setClock] = React.useState("");

  const activeCity = saved.find(c => c.id === activeId) || saved[0];

  React.useEffect(() => { try { localStorage.setItem("wm_cities", JSON.stringify(saved)); } catch (e) {} }, [saved]);
  React.useEffect(() => { try { localStorage.setItem("wm_active", activeId); } catch (e) {} }, [activeId]);

  const loadWeather = React.useCallback(async (city) => {
    setLoading(true);
    try {
      const d = await WX.fetchWeather(city.lat, city.lon);
      setData(d); setSample(false);
    } catch (e) {
      setData(WX.sampleData()); setSample(true);
    }
    setLoading(false);
  }, []);

  React.useEffect(() => { if (activeCity) loadWeather(activeCity); }, [activeId]);

  // clock at city local time
  React.useEffect(() => {
    if (!data) return;
    const tick = () => {
      const now = new Date();
      const utc = now.getTime() + now.getTimezoneOffset() * 60000;
      const ct = new Date(utc + (data.utcOffsetSec || 0) * 1000);
      let h = ct.getHours(); const m = ct.getMinutes();
      const ap = h >= 12 ? "PM" : "AM"; h = h % 12 || 12;
      setClock(`${h}:${String(m).padStart(2, "0")}`);
    };
    tick(); const id = setInterval(tick, 10000);
    return () => clearInterval(id);
  }, [data]);

  const ptr = usePullToRefresh(() => loadWeather(activeCity));

  // ---- effective display (apply tweaks overrides) ----
  const baseCond = data ? WX.conditionOf(data.current.code) : "clear";
  const forcedCond = t.forceWeather === "Auto" ? null : COND_BY_LABEL[t.forceWeather];
  const cond = forcedCond || baseCond;
  const isDay = !data ? false : (t.timeOfDay === "Auto" ? data.current.isDay : t.timeOfDay === "Day");
  const theme = WX.themeFor(cond, isDay);
  const animate = t.animations;

  const displayData = React.useMemo(() => {
    if (!data) return null;
    if (!forcedCond && t.timeOfDay === "Auto") return data;
    const code = forcedCond ? CODE_BY_COND[forcedCond] : data.current.code;
    const dayv = t.timeOfDay === "Auto" ? data.current.isDay : t.timeOfDay === "Day";
    return { ...data, current: { ...data.current, code, isDay: dayv } };
  }, [data, forcedCond, t.timeOfDay]);

  // ---- city management ----
  const addCity = (r) => {
    const city = { id: String(r.id), name: r.name, admin: r.admin, country: r.country, lat: r.lat, lon: r.lon };
    setSaved(prev => prev.find(c => c.id === city.id) ? prev : [...prev, city]);
    setActiveId(city.id); setView("home");
  };
  const selectCity = (c) => { setActiveId(c.id); setView("home"); };
  const removeCity = (c) => {
    setSaved(prev => {
      const next = prev.filter(x => x.id !== c.id);
      if (c.id === activeId && next.length) setActiveId(next[0].id);
      return next.length ? next : [DEFAULT_CITY];
    });
  };

  return (
    <div className="stage">
      <div className="device" style={{ "--theme-sub": theme.sub }}>
        <WeatherBackground condition={cond} isDay={isDay} animate={animate} theme={theme} />

        {sample && <div className="offline-pill">Demo data · live feed unavailable</div>}

        {view === "home" && (
          <div className="screen">
            <StatusBar time={clock} />
            {!displayData ? <Loader theme={theme} /> : (
              <HomeScreen data={displayData} unit={unit} animate={animate} theme={theme}
                city={activeCity} style={t.style} forecastMode={forecastMode}
                setForecastMode={setForecastMode} ptr={ptr} />
            )}
            <UnitToggle unit={unit} onToggle={() => setTweak("units", unit === "c" ? "°F" : "°C")} />
            <BottomNav view={view} onSearch={() => setView("search")}
              onList={() => setForecastMode(m => m === "hourly" ? "weekly" : "hourly")}
              onHome={() => setView("home")} onRadar={() => setView("radar")}
              onPrefs={() => setView("prefs")} />
          </div>
        )}

        {view === "home" && loading && displayData && (
          <div style={{ position: "absolute", top: 16, left: "50%", transform: "translateX(-50%)", zIndex: 6 }}>
            <div className="ptr-spinner spin" style={{ animation: "spin 0.7s linear infinite", width: 18, height: 18, opacity: 0.6 }} />
          </div>
        )}

        {view === "search" && (
          <SearchScreen saved={saved} activeId={activeId} unit={unit}
            onSelect={selectCity} onAdd={addCity} onRemove={removeCity}
            onClose={() => setView("home")} />
        )}

        {view === "radar" && (
          <RadarScreen city={activeCity} onClose={() => setView("home")} />
        )}

        <TweaksPanel>
          <TweakSection label="Look & feel" />
          <TweakRadio label="Layout" value={t.style} options={["classic", "novel"]} onChange={v => setTweak("style", v)} />
          <TweakRadio label="Units" value={t.units} options={["°C", "°F"]} onChange={v => setTweak("units", v)} />
          <TweakToggle label="Weather motion" value={t.animations} onChange={v => setTweak("animations", v)} />
          <TweakSection label="Preview conditions" />
          <TweakSelect label="Time of day" value={t.timeOfDay} options={["Auto", "Day", "Night"]} onChange={v => setTweak("timeOfDay", v)} />
          <TweakSelect label="Force weather" value={t.forceWeather}
            options={["Auto", "Clear", "Partly Cloudy", "Cloudy", "Fog", "Rain", "Snow", "Thunderstorm"]}
            onChange={v => setTweak("forceWeather", v)} />
        </TweaksPanel>
      </div>
    </div>
  );
}

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