"use client";

import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { WeekCalendar } from "./WeekCalendar";
import { MobileCardList } from "./MobileCardList";
import { WeekNav } from "./WeekNav";
import { Legend } from "./Legend";
import { EmptyState } from "./EmptyState";
import { PARKS, groupByRegion } from "@/lib/parks";
import type { DayData } from "@/lib/types";

const REFRESH_INTERVAL_MS = 2 * 60 * 1000; // 2 minutes
const OPEN_REFRESH_BUFFER_MS = 30_000;      // 30s after opening time before hitting the API

/** Parse the opening hour/minute from a hoursLabel like "10am", "10:30am", "11am". */
function parseOpenTime(hoursLabel: string): { hour: number; minute: number } | null {
  const openPart = hoursLabel.split(" - ")[0].trim();
  const match = openPart.match(/^(\d+)(?::(\d+))?(am|pm)$/i);
  if (!match) return null;
  let hour = parseInt(match[1], 10);
  const minute = match[2] ? parseInt(match[2], 10) : 0;
  const period = match[3].toLowerCase();
  if (period === "pm" && hour !== 12) hour += 12;
  if (period === "am" && hour === 12) hour = 0;
  return { hour, minute };
}

/** Milliseconds from now until a given local clock time in a timezone. Negative if already past. */
function msUntilLocalTime(hour: number, minute: number, timezone: string): number {
  const now = new Date();
  const parts = new Intl.DateTimeFormat("en-US", {
    timeZone: timezone,
    hour: "numeric",
    minute: "2-digit",
    hour12: false,
  }).formatToParts(now);
  const localHour   = parseInt(parts.find(p => p.type === "hour")!.value, 10) % 24;
  const localMinute = parseInt(parts.find(p => p.type === "minute")!.value, 10);
  return ((hour * 60 + minute) - (localHour * 60 + localMinute)) * 60_000;
}

const COASTER_MODE_KEY = "coasterMode";

interface HomePageClientProps {
  weekStart: string;
  weekDates: string[];
  today: string;
  isCurrentWeek: boolean;
  data: Record<string, Record<string, DayData>>;
  rideCounts: Record<string, number>;
  coasterCounts: Record<string, number>;
  openParkIds: string[];
  closingParkIds: string[];
  weatherDelayParkIds: string[];
  hasCoasterData: boolean;
  scrapedCount: number;
}

export function HomePageClient({
  weekStart,
  weekDates,
  today,
  isCurrentWeek,
  data,
  rideCounts,
  coasterCounts,
  openParkIds,
  closingParkIds,
  weatherDelayParkIds,
  hasCoasterData,
  scrapedCount,
}: HomePageClientProps) {
  const router = useRouter();
  const [coastersOnly, setCoastersOnly] = useState(false);

  // Hydrate from localStorage after mount to avoid SSR mismatch.
  useEffect(() => {
    setCoastersOnly(localStorage.getItem(COASTER_MODE_KEY) === "true");
  }, []);

  // Periodically re-fetch server data (ride counts, open status) without a full page reload.
  useEffect(() => {
    if (!isCurrentWeek) return;
    const id = setInterval(() => router.refresh(), REFRESH_INTERVAL_MS);
    return () => clearInterval(id);
  }, [isCurrentWeek, router]);

  // Schedule a targeted refresh at each park's exact opening time so the
  // open indicator and ride counts appear immediately rather than waiting
  // up to 2 minutes for the next polling cycle.
  useEffect(() => {
    if (!isCurrentWeek) return;
    const timeouts: ReturnType<typeof setTimeout>[] = [];

    for (const park of PARKS) {
      const dayData = data[park.id]?.[today];
      if (!dayData?.isOpen || !dayData.hoursLabel) continue;
      const openTime = parseOpenTime(dayData.hoursLabel);
      if (!openTime) continue;
      const ms = msUntilLocalTime(openTime.hour, openTime.minute, park.timezone);
      // Only schedule if opening is still in the future (within the next 24h)
      if (ms > 0 && ms < 24 * 60 * 60 * 1000) {
        timeouts.push(setTimeout(() => router.refresh(), ms));                          // mark as open
        timeouts.push(setTimeout(() => router.refresh(), ms + OPEN_REFRESH_BUFFER_MS)); // pick up ride counts
      }
    }

    return () => timeouts.forEach(clearTimeout);
  }, [isCurrentWeek, today, data, router]);

  const toggle = () => {
    const next = !coastersOnly;
    setCoastersOnly(next);
    localStorage.setItem(COASTER_MODE_KEY, String(next));
  };

  const activeCounts = coastersOnly ? coasterCounts : rideCounts;

  const visibleParks = PARKS.filter((park) =>
    weekDates.some((date) => data[park.id]?.[date]?.isOpen)
  );
  const grouped = groupByRegion(visibleParks);

  return (
    <div style={{ minHeight: "100vh", background: "var(--color-bg)" }}>
      {/* ── Header ───────────────────────────────────────────────────────────── */}
      <header style={{
        position: "sticky",
        top: 0,
        zIndex: 20,
        background: "var(--color-bg)",
        borderBottom: "1px solid var(--color-border)",
      }}>
        {/* Row 1: Title + controls */}
        <div style={{
          padding: "12px 16px 10px",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          gap: 12,
        }}>
          <span style={{
            fontSize: "1.1rem",
            fontWeight: 700,
            color: "var(--color-text)",
            letterSpacing: "-0.02em",
          }}>
            Thoosie Calendar
          </span>

          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {hasCoasterData && (
              <button
                onClick={toggle}
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 5,
                  padding: "4px 12px",
                  borderRadius: 20,
                  border: coastersOnly
                    ? "1px solid var(--color-accent)"
                    : "1px solid var(--color-border)",
                  background: coastersOnly
                    ? "var(--color-accent-muted)"
                    : "var(--color-surface)",
                  color: coastersOnly
                    ? "var(--color-accent)"
                    : "var(--color-text-muted)",
                  fontSize: "0.72rem",
                  fontWeight: 600,
                  cursor: "pointer",
                  transition: "background 150ms ease, border-color 150ms ease, color 150ms ease",
                  whiteSpace: "nowrap",
                }}
              >
                🎢 Coaster Mode
              </button>
            )}

            <span className="hidden sm:inline-flex" style={{
              background: visibleParks.length > 0 ? "var(--color-open-bg)" : "var(--color-surface)",
              border: `1px solid ${visibleParks.length > 0 ? "var(--color-open-border)" : "var(--color-border)"}`,
              borderRadius: 20,
              padding: "4px 14px",
              fontSize: "0.78rem",
              color: visibleParks.length > 0 ? "var(--color-open-hours)" : "var(--color-text-muted)",
              fontWeight: 600,
              alignItems: "center",
              whiteSpace: "nowrap",
            }}>
              {visibleParks.length} of {PARKS.length} parks open this week
            </span>
          </div>
        </div>

        {/* Row 2: Week nav + legend */}
        <div style={{
          padding: "8px 16px 10px",
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          gap: 16,
          borderTop: "1px solid var(--color-border-subtle)",
        }}>
          <WeekNav
            weekStart={weekStart}
            weekDates={weekDates}
            isCurrentWeek={isCurrentWeek}
          />
          <div className="hidden sm:flex">
            <Legend />
          </div>
        </div>
      </header>

      {/* ── Main content ────────────────────────────────────────────────────── */}
      <main className="px-4 sm:px-6 pb-12">
        {scrapedCount === 0 ? (
          <EmptyState />
        ) : (
          <>
            {/* Mobile: card list (hidden on lg+) */}
            <div className="lg:hidden">
              <MobileCardList
                grouped={grouped}
                weekDates={weekDates}
                data={data}
                today={today}
                rideCounts={activeCounts}
                coastersOnly={coastersOnly}
                openParkIds={openParkIds}
                closingParkIds={closingParkIds}
                weatherDelayParkIds={weatherDelayParkIds}
              />
            </div>

            {/* Desktop: week table (hidden below lg) */}
            <div className="hidden lg:block">
              <WeekCalendar
                parks={visibleParks}
                weekDates={weekDates}
                data={data}
                grouped={grouped}
                rideCounts={activeCounts}
                coastersOnly={coastersOnly}
                openParkIds={openParkIds}
                closingParkIds={closingParkIds}
                weatherDelayParkIds={weatherDelayParkIds}
              />
            </div>
          </>
        )}
      </main>
    </div>
  );
}
