import { useEffect, useState } from "react";
import type {
  CardLayout,
  ClockCard,
  CustomJsonCard,
  DataCard,
  ImageRotatorCard,
  StaticTextCard,
} from "../types";
import { evaluatePath } from "../utils/evaluatePath";

// ─── Shared card shell ────────────────────────────────────────────────────────

function CardShell({ name, children, footer }: { name: string; children: React.ReactNode; footer?: React.ReactNode }) {
  return (
    <div className="flex flex-col gap-1 bg-black/40 backdrop-blur-sm rounded-2xl border border-white/10 px-5 py-4 w-full h-full overflow-hidden">
      <span className="text-gray-400 text-xs font-semibold uppercase tracking-wider truncate shrink-0">
        {name}
      </span>
      <div className="flex-1 overflow-hidden min-h-0">{children}</div>
      {footer && <div className="shrink-0">{footer}</div>}
    </div>
  );
}

// ─── custom_json widget ───────────────────────────────────────────────────────

function CustomJsonWidget({ card, layout }: { card: CustomJsonCard; layout?: CardLayout }) {
  const [value, setValue] = useState<string>("…");
  const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [now, setNow] = useState<Date>(() => new Date());
  const [pulling, setPulling] = useState(false);
  const [dots, setDots] = useState(0);
  const [responseMs, setResponseMs] = useState<number | null>(null);

  useEffect(() => {
    const ticker = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(ticker);
  }, []);

  useEffect(() => {
    if (!pulling) return;
    const dotsTimer = setInterval(() => setDots((d) => (d + 1) % 4), 400);
    return () => clearInterval(dotsTimer);
  }, [pulling]);

  useEffect(() => {
    const fetchData = () => {
      setPulling(true);
      setDots(0);
      const start = performance.now();
      const headers: Record<string, string> = {
        Accept: "application/json",
        ...(card.config.additional_headers ?? {}),
      };
      fetch(card.config.url, { headers })
        .then((r) => r.json())
        .then((data) => {
          const result = card.config.take ? evaluatePath(data, card.config.take) : data;
          const display =
            result === null || result === undefined
              ? "(null)"
              : typeof result === "object"
                ? JSON.stringify(result, null, 2)
                : String(result);
          setValue(display);
          setLastUpdated(new Date());
          setResponseMs(Math.round(performance.now() - start));
          setError(null);
          setPulling(false);
        })
        .catch((err) => {
          setResponseMs(Math.round(performance.now() - start));
          setError(String(err));
          setPulling(false);
        });
    };

    fetchData();
    const ms = Math.max(5000, (card.config.refresh_interval ?? 60) * 1000);
    const interval = setInterval(fetchData, ms);
    return () => clearInterval(interval);
  }, [card.id, card.config.url, card.config.refresh_interval, card.config.take]);

  const refreshMs = Math.max(5000, (card.config.refresh_interval ?? 60) * 1000);
  const secAgo = lastUpdated ? Math.floor((now.getTime() - lastUpdated.getTime()) / 1000) : null;
  const nextIn = lastUpdated
    ? Math.max(0, Math.ceil((lastUpdated.getTime() + refreshMs - now.getTime()) / 1000))
    : null;

  const baseFontSize = card.config.display_options?.font_size ?? 16;
  const textColor = card.config.display_options?.text_color ?? "#ffffff";
  const colSpan = layout?.col_span ?? 1;
  const rowSpan = layout?.row_span ?? 1;
  const fontSize = Math.round(baseFontSize * Math.sqrt(colSpan * rowSpan));
  const centered = colSpan > 1 || rowSpan > 1;

  return (
    <CardShell
      name={card.name}
      footer={
        pulling ? (
          <span className="text-gray-500 text-xs">pulling{"." .repeat(dots)}</span>
        ) : secAgo !== null && nextIn !== null ? (
          <span className="text-gray-600 text-xs">
            {secAgo}s ago · next in {nextIn}s{responseMs !== null ? ` · ${responseMs}ms` : ""}
          </span>
        ) : undefined
      }
    >
      {error ? (
        <span className="text-red-400 text-sm break-all">⚠ {error}</span>
      ) : (
        <div className={`flex h-full overflow-hidden${centered ? " items-center justify-center" : ""}`}>
          <span
            className={`font-mono break-all whitespace-pre-wrap leading-snug${centered ? " text-center" : " block"}`}
            style={{ fontSize, color: textColor }}
          >
            {value}
          </span>
        </div>
      )}
    </CardShell>
  );
}

// ─── static_text widget ───────────────────────────────────────────────────────

function StaticTextWidget({ card, layout }: { card: StaticTextCard; layout?: CardLayout }) {
  const baseFontSize = card.config.font_size ?? 16;
  const textColor = card.config.text_color ?? "#ffffff";
  const colSpan = layout?.col_span ?? 1;
  const rowSpan = layout?.row_span ?? 1;
  const fontSize = Math.round(baseFontSize * Math.sqrt(colSpan * rowSpan));
  const centered = colSpan > 1 || rowSpan > 1;

  return (
    <CardShell name={card.name}>
      <div className={`flex h-full overflow-hidden${centered ? " items-center justify-center" : ""}`}>
        <span
          className={`whitespace-pre-wrap break-words leading-snug${centered ? " text-center" : " block"}`}
          style={{ fontSize, color: textColor }}
        >
          {card.config.text}
        </span>
      </div>
    </CardShell>
  );
}

// ─── clock widget ─────────────────────────────────────────────────────────────

function formatDuration(totalSeconds: number): string {
  if (totalSeconds <= 0) return "00:00:00";
  const d = Math.floor(totalSeconds / 86400);
  const h = Math.floor((totalSeconds % 86400) / 3600);
  const m = Math.floor((totalSeconds % 3600) / 60);
  const s = totalSeconds % 60;
  const timePart = [String(h).padStart(2, "0"), String(m).padStart(2, "0"), String(s).padStart(2, "0")].join(":");
  return d > 0 ? `${d}d ${timePart}` : timePart;
}

function ClockWidget({ card, layout }: { card: ClockCard; layout?: CardLayout }) {
  const [now, setNow] = useState<Date>(() => new Date());

  useEffect(() => {
    const ticker = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(ticker);
  }, []);

  const baseFontSize = card.config.font_size ?? 48;
  const textColor = card.config.text_color ?? "#ffffff";
  const colSpan = layout?.col_span ?? 1;
  const rowSpan = layout?.row_span ?? 1;
  const fontSize = Math.round(baseFontSize * Math.sqrt(colSpan * rowSpan));
  const centered = colSpan > 1 || rowSpan > 1;

  let display = "";
  let subtitle = "";

  if (card.config.mode === "time") {
    const tz = card.config.timezone;
    const showSec = card.config.show_seconds !== false;
    try {
      display = new Intl.DateTimeFormat("en-GB", {
        hour: "2-digit",
        minute: "2-digit",
        second: showSec ? "2-digit" : undefined,
        hour12: false,
        timeZone: tz || undefined,
      }).format(now);
    } catch {
      display = now.toLocaleTimeString();
    }
    if (tz) subtitle = tz.replace("_", " ");
  } else {
    // timer / countdown
    const target = card.config.target_iso ? new Date(card.config.target_iso) : null;
    if (!target || isNaN(target.getTime())) {
      display = "invalid target";
    } else {
      const diff = Math.max(0, Math.floor((target.getTime() - now.getTime()) / 1000));
      if (diff === 0) {
        display = "00:00";
        subtitle = "Time's up!";
      } else {
        display = formatDuration(diff);
        subtitle = `until ${new Intl.DateTimeFormat("en-GB", {
          dateStyle: "medium",
          timeStyle: "short",
          timeZone: card.config.timezone || undefined,
        }).format(target)}`;
      }
    }
  }

  return (
    <CardShell name={card.name}>
      <div className={`flex flex-col justify-center h-full gap-1${centered ? " items-center" : ""}`}>
        <span
          className={`font-mono tabular-nums leading-none${centered ? " text-center" : ""}`}
          style={{ fontSize, color: textColor }}
        >
          {display}
        </span>
        {subtitle && (
          <span className={`text-gray-500 text-xs mt-1${centered ? " text-center" : ""}`}>{subtitle}</span>
        )}
      </div>
    </CardShell>
  );
}

// ─── image_rotator widget ─────────────────────────────────────────────────────

function ImageRotatorWidget({ card }: { card: ImageRotatorCard }) {
  const images = card.config.images ?? [];
  const [index, setIndex] = useState(0);
  const [fade, setFade] = useState(true);

  useEffect(() => {
    if (images.length <= 1) return;
    const ms = Math.max(2000, (card.config.interval ?? 10) * 1000);
    const timer = setInterval(() => {
      setFade(false);
      setTimeout(() => {
        setIndex((i) => (i + 1) % images.length);
        setFade(true);
      }, 400);
    }, ms);
    return () => clearInterval(timer);
  }, [images.length, card.config.interval]);

  if (images.length === 0) {
    return (
      <CardShell name={card.name}>
        <span className="text-gray-500 text-sm">No images configured.</span>
      </CardShell>
    );
  }

  const fit = card.config.fit === "contain" ? "contain" : "cover";

  return (
    <div className="relative w-full h-full overflow-hidden rounded-2xl">
      <img
        key={images[index]}
        src={images[index]}
        alt=""
        style={{
          width: "100%",
          height: "100%",
          objectFit: fit,
          transition: "opacity 0.4s ease",
          opacity: fade ? 1 : 0,
          display: "block",
        }}
      />
      {/* Name overlay */}
      <div className="absolute bottom-0 left-0 right-0 px-4 py-2 bg-gradient-to-t from-black/70 to-transparent">
        <span className="text-white text-xs font-semibold truncate">{card.name}</span>
        {images.length > 1 && (
          <span className="text-white/50 text-xs ml-2">
            {index + 1}/{images.length}
          </span>
        )}
      </div>
    </div>
  );
}

// ─── Dispatcher ───────────────────────────────────────────────────────────────

export function DataCardWidget({ card, layout }: { card: DataCard; layout?: CardLayout }) {
  if (card.type === "static_text") return <StaticTextWidget card={card} layout={layout} />;
  if (card.type === "clock") return <ClockWidget card={card} layout={layout} />;
  if (card.type === "image_rotator") return <ImageRotatorWidget card={card} />;
  // default: custom_json
  return <CustomJsonWidget card={card as CustomJsonCard} layout={layout} />;
}
