"use client";

import { useEffect, useRef, useState } from "react";
import Link from "next/link";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import Icon from "@/components/ui/Icon";
import { day, deg, look } from "@/components/services/WeatherForecast";
import type { Forecast } from "@/lib/api/climate";
import { useCitiesStore } from "@/store/cities";
import { useForecastStore } from "@/store/climate";

const CINE = [0.77, 0, 0.175, 1] as const;
const OUT = [0.2, 0.7, 0.2, 1] as const;

/** One background photo. `x`/`y`/`r` set the circle it grows from: the city tab that was clicked. */
type Layer = { key: number; cityId: number; x: number; y: number; r: number };

/**
 * Home: live weather across Syria. The city photo fills the panel; picking another city grows its photo out of
 * the clicked tab as an expanding circle, the city name rises letter by letter and the 7-day strip refreshes.
 */
export default function Weather() {
  const reduce = useReducedMotion();
  const cities = useCitiesStore();
  const forecast = useForecastStore();
  const panel = useRef<HTMLDivElement>(null);
  const seq = useRef(0);
  // Forecasts already fetched this visit, so switching back to a city is instant.
  const cache = useRef(new Map<number, Forecast>());
  const [layers, setLayers] = useState<Layer[]>([]);

  useEffect(() => {
    if (cities.status === "idle") void cities.load();
  }, [cities.status, cities.load]);

  // Warm the cache for every city photo so a reveal never wipes in an empty frame.
  useEffect(() => {
    cities.items.forEach((c) => c.cover?.url && (new Image().src = c.cover.url));
  }, [cities.items]);

  const cityId = layers.at(-1)?.cityId ?? cities.items[0]?.id;
  const city = cities.items.find((c) => c.id === cityId);

  if (forecast.item) cache.current.set(forecast.item.city.id, forecast.item);
  const f = cityId === undefined ? null : (cache.current.get(cityId) ?? null);

  useEffect(() => {
    if (cityId !== undefined && !cache.current.has(cityId)) void forecast.load(cityId);
  }, [cityId, forecast.load]);

  const shown: Layer[] = layers.length ? layers : cityId !== undefined ? [{ key: 0, cityId, x: 0, y: 0, r: 0 }] : [];

  const pick = (id: number, e: React.MouseEvent<HTMLButtonElement>) => {
    if (id === cityId || !panel.current) return;
    const box = panel.current.getBoundingClientRect();
    const tab = e.currentTarget.getBoundingClientRect();
    const x = tab.left + tab.width / 2 - box.left;
    const y = tab.top + tab.height / 2 - box.top;
    const r = Math.hypot(Math.max(x, box.width - x), Math.max(y, box.height - y));
    // Keep the photo on screen underneath (the first time, the initial city) and grow the new one over it.
    setLayers((l) => [...(l.length ? l.slice(-1) : shown), { key: ++seq.current, cityId: id, x, y, r }]);
  };

  const failed = forecast.status === "error" && !f;
  const current = f?.current;

  return (
    <section className="wxh" aria-labelledby="wxh-h">
      <div className="wxh-wrap">
        <div className="wxh-panel" ref={panel}>
          <div className="wxh-bg" aria-hidden="true">
            {shown.map((l) => {
              const src = cities.items.find((c) => c.id === l.cityId)?.cover?.url;
              const reveal = l.key !== 0 && !reduce;
              return (
                <motion.div
                  key={l.key}
                  className="wxh-layer"
                  initial={reveal ? { clipPath: `circle(0px at ${l.x}px ${l.y}px)` } : false}
                  animate={reveal ? { clipPath: `circle(${l.r}px at ${l.x}px ${l.y}px)` } : undefined}
                  transition={{ duration: 0.95, ease: CINE }}
                  onAnimationComplete={() => setLayers((all) => (all.at(-1)?.key === l.key ? [l] : all))}
                >
                  {src && <motion.img src={src} alt="" initial={reveal ? { scale: 1.18 } : false} animate={{ scale: 1 }} transition={{ duration: 1.4, ease: OUT }} />}
                </motion.div>
              );
            })}
          </div>

          <div className="wxh-top">
            <div className="wxh-head">
              <h2 id="wxh-h">Weather across Syria</h2>
              <Link className="wxh-more" href="/services/calendar">
                Full calendar <Icon name="arrow_forward" className="arrow" />
              </Link>
            </div>
            <div className="wxh-tabs" role="group" aria-label="City" data-lenis-prevent>
              {cities.items.map((c) => (
                <button key={c.id} type="button" className="wxh-tab" aria-pressed={c.id === cityId} onClick={(e) => pick(c.id, e)}>
                  {c.id === cityId && !reduce && <motion.span layoutId="wxh-tab-pill" className="wxh-tab-pill" transition={{ type: "spring", stiffness: 420, damping: 36 }} />}
                  <span className="wxh-tab-label">{c.name}</span>
                </button>
              ))}
            </div>
          </div>

          <div className="wxh-main" aria-live="polite">
            <AnimatePresence mode="wait" initial={false}>
              {city && (
                <motion.h3 key={city.id} className="wxh-city" aria-label={city.name} exit={reduce ? undefined : { opacity: 0, y: -12, transition: { duration: 0.16 } }}>
                  {[...city.name].map((ch, i) => (
                    <span className="wxh-mask" key={i} aria-hidden="true">
                      <motion.span initial={reduce ? false : { y: "105%" }} animate={{ y: 0 }} transition={{ duration: 0.6, delay: 0.18 + i * 0.035, ease: OUT }}>
                        {ch === " " ? " " : ch}
                      </motion.span>
                    </span>
                  ))}
                </motion.h3>
              )}
            </AnimatePresence>

            <div className="wxh-now" data-loading={!f && !failed}>
              {failed ? (
                <p className="wxh-note">
                  {forecast.errorStatus === 503 ? "Live weather is unavailable right now." : "The forecast could not be loaded."}
                  <button type="button" onClick={() => cityId !== undefined && void forecast.load(cityId)}>
                    Try again
                  </button>
                </p>
              ) : (
                <>
                  <p className="wxh-temp">
                    {current && <Icon name={look(current.summary)[0]} />}
                    <span>{deg(current?.temp_c ?? null)}</span>
                  </p>
                  <p className="wxh-cond">
                    {current ? look(current.summary)[1] : "Loading the forecast"}
                    {current?.humidity != null && <span>Humidity {current.humidity}%</span>}
                    {current?.wind_speed_kmh != null && <span>Wind {Math.round(current.wind_speed_kmh)} km/h</span>}
                  </p>
                </>
              )}
            </div>
          </div>

          <ol className="wxh-days" aria-label="7-day forecast" data-loading={!f}>
            {(f?.daily ?? Array.from({ length: 7 }, () => null)).map((d, i) => (
              <li key={d?.date ?? i}>
                <span className="wxh-day">{d ? day(d.date, i) : " "}</span>
                <Icon name={d ? look(d.summary)[0] : "cloud"} />
                {d && <span className="sr-only">{look(d.summary)[1]}, </span>}
                <span className="wxh-range">
                  <b>{deg(d?.temp_max_c ?? null)}</b> {deg(d?.temp_min_c ?? null)}
                </span>
                <span className="wxh-rain">{d?.precipitation_probability ? `${d.precipitation_probability}% rain` : " "}</span>
              </li>
            ))}
          </ol>
        </div>
      </div>
    </section>
  );
}
