import { createFileRoute, Link } from "@tanstack/react-router";
import { useMemo, useState } from "react";
import { AppShell } from "@/components/AppShell";


import cityMumbai from "@/assets/city-mumbai.webp";
import { sourceCatalog, sevenDayForecast, tonightSnapshot } from "@/lib/quiet-hours-data";
import { useLocationInsight } from "@/hooks/use-location-insight";
import {
  useWeatherForecast,
  deriveAvoidHours,
  type AvoidHour,
  type WeatherForecastState,
} from "@/hooks/use-weather-forecast";
import { AlertTriangle, ChevronLeft, CloudSun } from "@/lib/icons";
import { useTonightSignal } from "@/hooks/use-gridpath";

export const Route = createFileRoute("/forecast")({
  head: () => ({
    meta: [
      { title: "Shared Hour Forecast — Quiet Hours" },
      { name: "description", content: "A seven-day look ahead at when timing matters most." },
      { property: "og:title", content: "Shared Hour Forecast" },
      {
        property: "og:description",
        content: "A seven-day look ahead at when timing matters most on the grid.",
      },
      { property: "og:image", content: cityMumbai },
    ],
  }),
  component: ForecastPage,
});

const bandColor: Record<string, string> = {
  Light: "var(--sage)",
  Easy: "var(--sage)",
  Comfortable: "var(--sage)",
  Flexible: "var(--sage)",
  Windy: "oklch(0.72 0.08 220)",
  Elevated: "var(--amber)",
  High: "oklch(0.62 0.14 35)",
};

function ForecastPage() {
  const [open, setOpen] = useState<string | null>("Tue");
  const { insight, coords } = useLocationInsight();
  const showDefaultForecast = !insight || insight.region === tonightSnapshot.region;
  const sources = insight?.sources
    .map((sourceId) => sourceCatalog.find((source) => source.id === sourceId)?.name)
    .filter(Boolean)
    .slice(0, 4);
  const weather = useWeatherForecast(coords);
  const avoidHours = useMemo(() => deriveAvoidHours(weather.periods), [weather.periods]);

  return (
    <AppShell>
      {/* Hero band — Mumbai at dusk, evokes a city of shared evening hours */}
      <section className="relative overflow-hidden">
        <img
          src={cityMumbai}
          alt="Mumbai skyline at dusk with lit windows"
          fetchPriority="high"
          decoding="async"
          className="absolute inset-0 h-full w-full object-cover animate-soft-fade"
        />
        <div
          className="absolute inset-0"
          style={{
            background:
              "linear-gradient(180deg, oklch(0.18 0.03 60 / 0.45) 0%, oklch(0.18 0.03 60 / 0.65) 55%, var(--background) 100%)",
          }}
          aria-hidden
        />
        <div className="relative z-10 px-6 pt-8 pb-10">
          <Link
            to="/"
            className="inline-flex items-center gap-1 text-xs uppercase tracking-[0.18em] text-white/80 hover:text-white"
          >
            <ChevronLeft className="h-3 w-3" /> Back
          </Link>
          <div className="mt-6 animate-fade-rise">
            <div className="text-[11px] uppercase tracking-[0.22em] text-white/80">
              {insight ? `Look ahead · ${insight.label}` : "Look ahead"}
            </div>
            <h1 className="font-serif text-[36px] leading-[1.05] text-white mt-2">
              Shared Hour Forecast
            </h1>
            <p className="text-white/85 mt-3 text-[14px] leading-relaxed max-w-[34ch]">
              {insight
                ? `Source context is set to ${insight.gridName}.`
                : "Set your area on Home to tune this forecast to local public sources."}
            </p>
          </div>
        </div>
      </section>

      <section className="px-6 mb-3 space-y-3">
        <AvoidHoursPanel weather={weather} avoidHours={avoidHours} hasCoords={Boolean(coords)} />
        <TonightTickCard region={insight?.region ?? null} />
      </section>

      <section className="px-6 space-y-2">
        {showDefaultForecast ? (
          sevenDayForecast.map((d, i) => {
            const isOpen = open === d.day;
            return (
              <button
                key={d.day}
                onClick={() => setOpen(isOpen ? null : d.day)}
                className={`w-full text-left bg-card border border-border rounded-3xl p-5 transition-all animate-fade-rise delay-${Math.min(i + 1, 5)}`}
                style={{ boxShadow: "var(--shadow-soft)" }}
              >
                <div className="flex items-center gap-4">
                  <div className="w-14">
                    <div className="font-serif text-2xl leading-none">{d.day}</div>
                    <div className="text-[10px] uppercase tracking-wider text-muted-foreground mt-1">
                      {d.date}
                    </div>
                  </div>
                  <div className="flex-1">
                    <div className="text-[15px] font-medium">{d.band}</div>
                    <div className="h-1.5 mt-2 rounded-full bg-muted overflow-hidden">
                      <div
                        className="h-full rounded-full transition-all"
                        style={{ width: `${d.level * 100}%`, background: bandColor[d.band] }}
                      />
                    </div>
                  </div>
                </div>
                {isOpen && (
                  <p className="text-sm text-muted-foreground mt-4 leading-relaxed">{d.reason}</p>
                )}
              </button>
            );
          })
        ) : (
          <LocalForecastCard
            insight={insight}
            weather={weather}
            sources={sources}
            hasCoords={Boolean(coords)}
          />
        )}

        <Link
          to="/tonight"
          className="mt-6 block text-center rounded-2xl border border-border bg-card py-3.5 text-sm"
        >
          See tonight in detail
        </Link>
      </section>
    </AppShell>
  );
}

function AvoidHoursPanel({
  weather,
  avoidHours,
  hasCoords,
}: {
  weather: WeatherForecastState;
  avoidHours: AvoidHour[];
  hasCoords: boolean;
}) {
  if (!hasCoords) {
    return (
      <div
        className="rounded-3xl border border-border bg-card p-5 animate-fade-rise"
        style={{ boxShadow: "var(--shadow-soft)" }}
      >
        <div className="flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
          <CloudSun className="h-3.5 w-3.5" /> Avoid hours · Reference
        </div>
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          Set your area on Home to load tonight’s live NOAA hourly forecast and pinpoint avoid
          hours.
        </p>
        <div className="mt-3 rounded-2xl bg-secondary p-3 text-xs leading-relaxed">
          Reference window without location: <span className="font-medium">5–9 PM</span> (regional
          peak demand pattern).
        </div>
      </div>
    );
  }

  if (weather.status === "loading") {
    return (
      <div
        className="rounded-3xl border border-border bg-card p-5 animate-fade-rise"
        style={{ boxShadow: "var(--shadow-soft)" }}
      >
        <div className="flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
          <CloudSun className="h-3.5 w-3.5" /> Avoid hours · Loading
        </div>
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          Fetching live NOAA hourly forecast for your coordinates…
        </p>
      </div>
    );
  }

  if (weather.status === "error") {
    return (
      <div
        className="rounded-3xl border border-border bg-card p-5 animate-fade-rise"
        style={{ boxShadow: "var(--shadow-soft)" }}
      >
        <div className="flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
          <AlertTriangle className="h-3.5 w-3.5" /> Avoid hours · Live feed unavailable
        </div>
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          {weather.error ?? "NOAA forecast could not be reached."}
        </p>
        <div className="mt-3 rounded-2xl bg-secondary p-3 text-xs leading-relaxed">
          Reference window: <span className="font-medium">5–9 PM</span> (regional peak demand
          pattern).
        </div>
      </div>
    );
  }

  const peakLabel =
    avoidHours.length > 0
      ? avoidHours.map((h) => h.hourLabel).join(", ")
      : "No high-load hours flagged tonight.";
  const fetched = weather.fetchedAt
    ? weather.fetchedAt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })
    : "";

  return (
    <div
      className="rounded-3xl p-6 text-primary-foreground animate-fade-rise"
      style={{ background: "var(--gradient-night)", boxShadow: "var(--shadow-soft)" }}
    >
      <div className="flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] opacity-70">
        <CloudSun className="h-3.5 w-3.5" /> Avoid hours tonight · Live
      </div>
      <div className="font-serif text-2xl mt-2 leading-snug">{peakLabel}</div>
      {avoidHours.length > 0 && (
        <ul className="mt-4 space-y-2">
          {avoidHours.map((hour) => (
            <li
              key={hour.startTime}
              className="rounded-2xl bg-white/10 px-3 py-2 text-sm leading-snug"
            >
              <div className="flex items-center justify-between gap-3">
                <span className="font-medium">{hour.hourLabel}</span>
                <span className="text-xs opacity-80">
                  {hour.temperatureF}°F · {hour.shortForecast}
                </span>
              </div>
              <div className="mt-1 text-[11px] opacity-75">{hour.reasons.join(" · ")}</div>
            </li>
          ))}
        </ul>
      )}
      <div className="hairline my-5 opacity-30" />
      <div className="grid gap-1 text-[11px] leading-relaxed opacity-80">
        <div>
          <span className="font-medium">Live:</span> NOAA hourly forecast
          {fetched ? ` · fetched ${fetched}` : ""}
        </div>
        <div>
          <span className="font-medium">Reference:</span> peak demand window 4–9 PM (regional
          pattern)
        </div>
        <div className="opacity-70">
          Grid demand (CAISO/EIA) requires a server proxy and is not yet wired.
        </div>
      </div>
    </div>
  );
}

function TonightTickCard({
  region,
}: {
  region: import("@/lib/quiet-hours-data").RegionKey | null;
}) {
  const { data, isLoading, isError } = useTonightSignal(region);
  if (!region) return null;

  const bandLabel: Record<string, string> = {
    clean: "Clean",
    average: "Average",
    dirty: "High-carbon",
    unknown: "Unknown",
  };
  const bandTone: Record<string, string> = {
    clean: "var(--sage)",
    average: "var(--amber)",
    dirty: "oklch(0.62 0.14 35)",
    unknown: "var(--stone)",
  };

  return (
    <div
      className="rounded-3xl border border-border bg-card p-5 animate-fade-rise"
      style={{ boxShadow: "var(--shadow-soft)" }}
    >
      <div className="flex items-center justify-between gap-3">
        <div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
          Tonight's grid tick · {region}
        </div>
        <span className="text-[9px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-sage/20 text-foreground">
          Live
        </span>
      </div>
      {isLoading && <div className="mt-4 h-3 rounded-full bg-muted animate-pulse" />}
      {isError && (
        <div className="mt-3 text-xs text-muted-foreground">
          GridPath signal unavailable right now.
        </div>
      )}
      {data && (
        <>
          <div className="mt-3 font-serif text-2xl leading-snug">
            {bandLabel[data.moer.band] ?? "Unknown"} carbon intensity
          </div>
          <div className="mt-3 h-2 w-full overflow-hidden rounded-full bg-muted">
            <div
              className="h-full transition-all"
              style={{
                width: `${Math.min(100, Math.max(4, data.moer.percent ?? 0))}%`,
                background: bandTone[data.moer.band] ?? "var(--stone)",
              }}
            />
          </div>
          <p className="mt-3 text-xs text-muted-foreground leading-relaxed">
            {data.moer.value != null
              ? `${data.moer.value.toFixed(0)} ${data.moer.unit} · ${data.ba_name}`
              : `Live marginal emissions unavailable for ${data.ba_name} right now.`}
          </p>
        </>
      )}
    </div>
  );
}

function LocalForecastCard({
  insight,
  weather,
  sources,
  hasCoords,
}: {
  insight: import("@/lib/location-insights").LocationInsight;
  weather: WeatherForecastState;
  sources: (string | undefined)[] | undefined;
  hasCoords: boolean;
}) {
  // Build a 12-hour look-ahead from the NOAA hourly forecast.
  // Bar HEIGHT = relative temperature in this 12-hour window (always readable).
  // Bar COLOR = pressure on the grid (peak-window weight × heat).
  const series = useMemo(() => {
    if (weather.status !== "ready" || weather.periods.length === 0) return [];
    const next = weather.periods.slice(0, 12).map((p) => {
      const start = new Date(p.startTime);
      const hour = start.getHours();
      const tempF = p.temperatureUnit === "C" ? p.temperature * 1.8 + 32 : p.temperature;
      const peakCenter = 18;
      const peakWidth = 3;
      const peakWeight = Math.max(0, 1 - Math.abs(hour - peakCenter) / peakWidth);
      const heatWeight = Math.min(1, Math.max(0, (tempF - 60) / 35));
      const pressure = Math.min(1, peakWeight * 0.6 + heatWeight * 0.55);
      return {
        hour,
        label: start.toLocaleTimeString([], { hour: "numeric" }).replace(" ", ""),
        tempF: Math.round(tempF),
        pressure,
      };
    });
    const temps = next.map((s) => s.tempF);
    const minT = Math.min(...temps);
    const maxT = Math.max(...temps);
    const span = Math.max(1, maxT - minT);
    return next.map((s) => ({
      ...s,
      heightPct: 25 + ((s.tempF - minT) / span) * 70, // 25–95% so every bar is visible
    }));
  }, [weather.status, weather.periods]);

  return (
    <div
      className="rounded-3xl border border-border bg-card p-5 animate-fade-rise"
      style={{ boxShadow: "var(--shadow-soft)" }}
    >
      <div className="flex items-center justify-between gap-3">
        <div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
          Local forecast · next 12 hours
        </div>
        <span className="text-[9px] uppercase tracking-wider px-2 py-0.5 rounded-full bg-secondary text-muted-foreground shrink-0">
          NOAA · live
        </span>
      </div>
      <div className="mt-2 font-serif text-2xl leading-tight">
        {insight.gridName} outlook for {insight.label}
      </div>

      {!hasCoords && (
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          Set your area on Home to load the live NOAA hourly forecast for your coordinates.
        </p>
      )}

      {hasCoords && weather.status === "loading" && (
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          Fetching live NOAA hourly forecast…
        </p>
      )}

      {hasCoords && weather.status === "error" && (
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          {weather.error ?? "NOAA forecast could not be reached."} The seven-day regional curve
          isn't available for this area, but the live grid signal above still applies.
        </p>
      )}

      {hasCoords && weather.status === "ready" && series.length === 0 && (
        <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
          NOAA returned no hourly periods for this location. Try again in a few minutes.
        </p>
      )}

      {series.length > 0 && (
        <>
          <p className="mt-3 text-sm leading-relaxed text-muted-foreground">
            Bars show the next 12 hours of local temperature. Red bars sit inside the 4–9 PM peak
            window and combine heat with high demand — those are the hours where shifting helps
            most.
          </p>
          <div className="mt-4 flex items-end gap-1.5 h-32">
            {series.map((s, i) => (
              <div
                key={`${s.label}-${i}`}
                className="flex-1 rounded-t-md transition-all"
                style={{
                  height: `${s.heightPct}%`,
                  background:
                    s.pressure > 0.55
                      ? "oklch(0.62 0.14 35)"
                      : s.pressure > 0.25
                        ? "var(--amber)"
                        : "var(--sage)",
                }}
              />
            ))}
          </div>
          <div className="mt-1 flex gap-1.5">
            {series.map((s, i) => (
              <div
                key={`lbl-${i}`}
                className="flex-1 text-[9px] text-center tabular-nums text-muted-foreground"
              >
                {s.label}
              </div>
            ))}
          </div>
          <div className="mt-1 flex gap-1.5">
            {series.map((s, i) => (
              <div
                key={`t-${i}`}
                className="flex-1 text-[9px] text-center tabular-nums text-muted-foreground/70"
              >
                {s.tempF}°
              </div>
            ))}
          </div>
        </>
      )}

      {sources && sources.length > 0 && (
        <div className="mt-5 text-[11px] uppercase tracking-wide text-muted-foreground">
          Sources: {sources.join(" + ")}
        </div>
      )}
    </div>
  );
}
