"use client";

import { getLocation } from "@/lib/location";

import { useCallback, useEffect, useState } from "react";
import { MapPin } from "lucide-react";
import { sfx } from "@/lib/sfx";
import clsx from "clsx";

type Cond = "clear" | "cloud" | "rain" | "snow" | "storm" | "fog";
type Day = { day: string; condition: Cond; label: string; max: number; min: number; uv: number };
type Wx = {
  live: boolean;
  city: string;
  now: { temp: number; condition: Cond; label: string };
  days: Day[];
};

const GLYPH: Record<Cond, string> = {
  clear: "☀️", cloud: "☁️", rain: "🌧️", snow: "❄️", storm: "⛈️", fog: "🌫️",
};

/** Colour a bar by temperature, using the design's palette. */
function tempColour(t: number) {
  if (t <= 5) return { c: "#2b7cd3" };
  if (t <= 12) return { c: "#43a047" };
  if (t <= 20) return { c: "#f4b400" };
  if (t <= 27) return { c: "#ef6c00" };
  return { c: "#d32f2f" };
}

/** Panel tint follows the current condition rather than a UV band. */
const PANEL_BG: Record<Cond, string> = {
  clear: "linear-gradient(150deg,#f6a623,#ef6c00)",
  cloud: "linear-gradient(150deg,#6b7a8f,#475569)",
  rain: "linear-gradient(150deg,#3a6ea5,#1e3a5f)",
  snow: "linear-gradient(150deg,#7fb2e5,#3b82f6)",
  storm: "linear-gradient(150deg,#5b3f8f,#2a1b4a)",
  fog: "linear-gradient(150deg,#8b98a8,#5b6672)",
};

/** Counts the big number up rather than snapping to it. */
function useCountUp(target: number) {
  const [n, setN] = useState(target);
  useEffect(() => {
    const from = n;
    const t0 = performance.now();
    let raf = 0;
    const step = (t: number) => {
      const p = Math.min(1, (t - t0) / 700);
      const e = p * (2 - p);
      setN(Math.round(from + (target - from) * e));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [target]);
  return n;
}

/** Nominatim returns full official names; these are what people say. */
const SHORT_COUNTRY: Record<string, string> = {
  "United Kingdom of Great Britain and Northern Ireland": "UK",
  "United Kingdom": "UK",
  "United States of America": "USA",
  "United States": "USA",
};

function shortPlace(name: string) {
  const parts = name.split(",").map((p) => p.trim());
  const last = parts[parts.length - 1];
  if (SHORT_COUNTRY[last]) parts[parts.length - 1] = SHORT_COUNTRY[last];
  return parts.join(", ");
}

export function WeatherWidget() {
  const [wx, setWx] = useState<Wx | null>(null);
  const [sel, setSel] = useState(0);

  useEffect(() => {
    const load = (lat?: number, lon?: number, city?: string) => {
      const p = new URLSearchParams();
      if (lat != null) p.set("lat", String(lat));
      if (lon != null) p.set("lon", String(lon));
      if (city) p.set("city", city);
      fetch(`/api/weather?${p}`)
        .then((r) => (r.ok ? r.json() : null))
        .then((d) => d && setWx(d))
        .catch(() => {});
    };

    // Load right away so the card isn't blank while geolocation resolves.
    load();

    getLocation().then(async (_c) => {
      if (!_c) return;
      const pos = { coords: { latitude: _c.lat, longitude: _c.lon } };
        const { latitude, longitude } = pos.coords;
        const r = await fetch(
          `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${latitude}&longitude=${longitude}&localityLanguage=en`
        ).catch(() => null);
        let city = "";
        if (r && r.ok) {
          const g = await r.json();
          city = [g.city || g.locality, g.countryName].filter(Boolean).join(", ");
        }
        load(latitude, longitude, city);
      });
  }, []);

  const days = wx?.days ?? [];
  const current = days[sel];
  const shownTemp = useCountUp(current?.max ?? wx?.now.temp ?? 0);
  const temps = days.map((d) => d.max);
  const lowT = temps.length ? Math.min(...temps) - 2 : 0;
  const span = temps.length ? Math.max(1, Math.max(...temps) - lowT) : 1;

  const pick = useCallback((i: number, u: number) => {
    setSel(i);
    sfx.click();
    void u;
  }, []);

  if (!wx) {
    return (
      <div className="uvw h-[190px] flex items-center justify-center">
        <span className="text-xs text-neutral-400">Loading weather…</span>
      </div>
    );
  }

  return (
    <div className="uvw">
      <div className="uvh">
        <span className="uv-cloud">{GLYPH[wx.now.condition]}</span>
        <div className="uv-loc min-w-0 flex-1">
          <b className="uv-loc-row truncate">
            <MapPin size={12} className="shrink-0" />
            {wx.city || "Your area"}
          </b>
        </div>
      </div>

      <div className="uvbody">
        <div
          className="uv-panel-wrap"
          style={{ ["--panel-wash" as string]: PANEL_BG[current?.condition ?? wx.now.condition] }}
        >
        <div className="uv-panel">
          <span className="uv-cond-ico">{GLYPH[current?.condition ?? wx.now.condition]}</span>
          <span className="uv-temp">{shownTemp}°</span>
          <span className="uv-hilo">
            H {current?.max ?? wx.now.temp}° · L {current?.min ?? wx.now.temp}°
          </span>
        </div>
        </div>

        <div className="uv-bars">
          {days.map((d, i) => {
            const dl = tempColour(d.max);
            // Scale bars across the week's own range so differences show.
            const h = Math.max(14, ((d.max - lowT) / span) * 100);
            return (
              <button
                key={d.day + i}
                onClick={() => pick(i, d.uv)}
                className={clsx("uv-bar", i === sel && "sel")}
                title={`${d.label} · ${d.max}°/${d.min}°`}
              >
                <span className="uv-dayico">{GLYPH[d.condition]}</span>
                <span className="uv-track">
                  <span
                    className="uv-fill"
                    style={{
                      height: `${h}%`,
                      background: dl.c,
                      transitionDelay: `${i * 90}ms`,
                    }}
                  />
                  <span
                    className="uv-badge"
                    style={{
                      bottom: `${h}%`,
                      borderColor: dl.c,
                      transitionDelay: `${i * 90}ms`,
                    }}
                  >
                    {d.max}°
                  </span>
                </span>
                <span className="uv-day">{d.day}</span>
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}
