import { motion } from "framer-motion";
import {
  Film,
  Tv,
  Clapperboard,
  Settings,
  User,
  Plus,
  LogOut,
  ShieldCheck,
  Trophy,
} from "lucide-react";
import { isTizen, isWebOS } from "@/lib/platform";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import {
  useFocusable,
  setFocus as spatialSetFocus,
} from "@noriginmedia/norigin-spatial-navigation";
import AddServerDialog from "@/components/AddServerDialog";
import ExpiredOverlay from "@/components/ExpiredOverlay";
import LanguageSelect from "@/components/LanguageSelect";
import HeaderClock from "@/components/HeaderClock";
import HeaderMenu from "@/components/HeaderMenu";
import { FocusableSection, FocusableButton } from "@/components/focusable";
import { useProfiles } from "@/hooks/useProfiles";
import { useConnectProfile } from "@/hooks/useConnectProfile";
import { useAuth } from "@/hooks/useAuth";
import { apiSubscriptionStatus, type SubscriptionStatus } from "@/lib/nadiAuth";
import { playSelectSound, playMoveSound } from "@/lib/navSounds";

// ═══════════════════════════════════════════════════════════════════════
//   "Cyberpunk Luxury" tokens — bound to the SAME amber-gold the rest
//   of the app uses (`--primary: 40 80% 55%` → CSS class `gold-text`).
//   Any change to --primary in index.css cascades here automatically.
// ═══════════════════════════════════════════════════════════════════════
const GOLD = "hsl(40, 80%, 55%)";          // primary token, rich amber
const GOLD_SOFT = "hsla(40, 80%, 55%, 0.10)";
const GOLD_DEEP = "hsla(40, 80%, 55%, 0.04)";

/** Framer Motion variants for an individual category card.
 *  No borders, no box-shadow on the card itself — the focused glow is
 *  rendered by a separate `halo` sibling behind the tile so it can sit
 *  OUTSIDE the card rim with a small gap (floating halo look).         */
const cardVariants = {
  idle: {
    scale: 0.94,
    zIndex: 1,
    filter: "saturate(0.85) brightness(0.9)",
  },
  focused: {
    scale: 1.1,
    zIndex: 10,
    filter: "saturate(1.1) brightness(1.05)",
  },
} as const;

/** Halo sibling variants — lives BEHIND the card on a LARGER invisible
 *  div (`-inset-4` = -16px) so the gold box-shadow blooms outward from
 *  that wrapper's edge and never touches the card. This creates the
 *  visible transparent SPACE between the card and the floating gold
 *  shadow. No breathing — just a clean fade in/out on focus.          */
const haloVariants = {
  idle: { opacity: 0 },
  focused: { opacity: 1 },
} as const;

// ═══════════════════════════════════════════════════════════════════════
//   Category Card — spatial-navigation aware.
//   - `useFocusable` registers the node with norigin-spatial-navigation,
//     so Tizen / webOS remote arrows AND keyboard arrows move focus here.
//   - The parent <FocusableSection autoFocus> takes care of granting
//     initial focus to the first card when the page mounts.
//   - Mouse hover promotes itself to a focus event so the same gold ring
//     + sound triggers as remote / keyboard navigation.
//   - `tabIndex={0}` makes the element keyboard-reachable on web.
// ═══════════════════════════════════════════════════════════════════════
const CategoryCard = ({
  title,
  count,
  icon: Icon,
  index,
  route,
}: {
  title: string;
  count: string;
  icon: React.ElementType;
  index: number;
  route: string;
}) => {
  const navigate = useNavigate();

  const focusKey = `home-category-${index}`;
  const { ref, focused, focusKey: resolvedFocusKey } = useFocusable({
    focusKey,
    onEnterPress: () => {
      playSelectSound();
      navigate(route);
    },
    onFocus: ({ node }) => {
      playMoveSound();
      // Keep the tile visible even on tight 720p layouts.
      if (node) {
        (node as HTMLElement).scrollIntoView({
          behavior: "smooth",
          block: "nearest",
          inline: "center",
        });
      }
    },
  });

  const handleClick = () => {
    playSelectSound();
    navigate(route);
  };

  return (
    <motion.div
      ref={ref as unknown as React.Ref<HTMLDivElement>}
      layout
      initial={{ opacity: 0, y: 30 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{
        layout: { type: "spring", stiffness: 320, damping: 26 },
        opacity: { duration: 0.4, delay: index * 0.08 },
        y: { duration: 0.5, delay: index * 0.08 },
      }}
      role="button"
      tabIndex={0}
      data-focused={focused || undefined}
      data-testid={`home-category-card-${index}`}
      onClick={handleClick}
      onMouseEnter={() => {
        // Mouse / trackpad hover → promote to focus so the same gold
        // ring + animation runs as remote/keyboard navigation.
        if (resolvedFocusKey) spatialSetFocus(resolvedFocusKey);
      }}
      onKeyDown={(e) => {
        // Belt-and-braces: raw <Enter> / <Space> still activates, even if
        // the spatial-nav library is somehow disabled on older webOS TVs.
        if (e.key === "Enter" || e.key === " ") {
          e.preventDefault();
          handleClick();
        }
      }}
      className="relative cursor-pointer select-none w-[44%] sm:w-[180px] md:w-[240px] lg:w-[260px] outline-none"
      style={{
        // Establish a CSS containment context so the halo (and box-shadow
        // blur radii) can scale with the card's actual width using `cqw`
        // units. 1cqw = 1% of this wrapper's inline (width) size.
        // → On a 240px desktop card, 6.7cqw ≈ 16px (current desktop look);
        //   on a 150px mobile card, 6.7cqw ≈ 10px (proportionally identical).
        containerType: "inline-size",
      }}
    >
      {/* Floating gold SHADOW — proportional gap that scales WITH the card.
          `inset`, `border-radius`, and `box-shadow` blur/spread are all in
          `cqw` so the entire unit (card + floating halo) stays visually
          identical at every breakpoint. The halo radius is set to the
          card radius + the inset so the curve stays perfectly concentric
          with the card on the new 16:10 rectangle.                      */}
      <motion.div
        aria-hidden
        variants={haloVariants}
        animate={focused ? "focused" : "idle"}
        transition={{ duration: 0.3, ease: "easeOut" }}
        className="absolute pointer-events-none"
        style={{
          inset: "-3cqw",
          // card radius (5cqw) + inset (3cqw) = 8cqw → halo curve stays
          // concentric with the card edge on all four sides.
          borderRadius: "8cqw",
          // Tight, low-opacity gold bloom that hugs the rectangle. Two
          // layers: a soft inner edge and a wider, more diffused outer
          // glow. Spread + blur are proportional to card width.
          boxShadow: `0 0 10cqw 1cqw ${GOLD_SOFT}, 0 0 26cqw 3.5cqw ${GOLD_DEEP}`,
          willChange: "opacity",
        }}
      />

      <motion.div
        variants={cardVariants}
        animate={focused ? "focused" : "idle"}
        transition={{ type: "spring", stiffness: 280, damping: 22 }}
        className="relative overflow-hidden
                   w-full aspect-[16/10]
                   glass-card"
        style={{
          // Proportional rounding (5cqw ≈ 13px on a 260px card, 8px on
          // a 165px mobile card) so the halo stays perfectly concentric
          // with the card edge at every breakpoint.
          borderRadius: "5cqw",
          willChange: "transform",
        }}
      >
        <div className="relative z-10 h-full flex flex-col items-center justify-center gap-2 sm:gap-3 p-4 sm:p-5">
          {/* Icon — muted off-white (matches the header gear icon) when
              unfocused. On focus, transitions to solid GOLD (Nadi Player
              logo color) and starts the BLINK animation (opacity 1 ↔ 0,
              0.7s loop). On un-focus, smoothly fades back to muted white
              and stops blinking.                                        */}
          <motion.div
            animate={
              focused
                ? { opacity: [1, 0, 1], color: GOLD }
                : { opacity: 0.6, color: "#ffffff" }
            }
            transition={
              focused
                ? { duration: 0.7, repeat: Infinity, ease: "easeInOut" }
                : { duration: 0.25, ease: "easeOut" }
            }
            style={{ willChange: "opacity, color" }}
          >
            <Icon
              className={
                focused
                  ? "w-10 h-10 sm:w-14 sm:h-14 md:w-16 md:h-16"
                  : "w-8 h-8 sm:w-10 sm:h-10 md:w-12 md:h-12"
              }
              strokeWidth={1.2}
            />
          </motion.div>
          <motion.h3
            animate={{ color: focused ? "#fff" : "rgba(255,255,255,0.85)" }}
            className="text-sm sm:text-base md:text-lg font-medium tracking-wide"
          >
            {title}
          </motion.h3>
          <motion.p
            animate={{ opacity: focused ? 1 : 0.55 }}
            className="text-muted-foreground text-[10px] sm:text-xs"
          >
            {count}
          </motion.p>
        </div>
      </motion.div>
    </motion.div>
  );
};

const categoriesConfig = [
  { key: "liveTv", icon: Tv, route: "/live-tv" },
  { key: "movies", icon: Film, route: "/movies" },
  { key: "series", icon: Clapperboard, route: "/series" },
  // Samsung Tizen + LG webOS QA v1.4.3 — hide the World-Cup card from
  // the dashboard until the Samsung Apps store approves the build. The
  // feature ships unchanged on Android / web; only the entry point is
  // platform-gated. To re-enable on TVs after Samsung accepts, simply
  // drop the isTizen() / isWebOS() guards below.
  ...(isTizen() || isWebOS()
    ? []
    : [{ key: "worldCup", icon: Trophy, route: "/world-cup" }]),
] as const;

const Index = () => {
  const [showAddServer, setShowAddServer] = useState(false);
  const navigate = useNavigate();
  const { t } = useTranslation();
  const { activeProfile } = useProfiles();
  const connect = useConnectProfile();
  const { user, isGuest, logout } = useAuth();

  const isPaidUser = !!user && user.role === "user";

  const [sub, setSub] = useState<SubscriptionStatus | null>(null);

  useEffect(() => {
    if (!isPaidUser) return;
    let cancelled = false;
    apiSubscriptionStatus()
      .then((s) => {
        if (!cancelled) setSub(s);
      })
      .catch(() => { /* ignored */ });
    return () => { cancelled = true; };
  }, [isPaidUser, user?.id]);

  const daysRemaining = sub?.user.days_remaining ?? user?.days_remaining ?? null;
  const isExpired = sub?.user.is_expired ?? user?.is_expired ?? false;
  const expiryDate = sub?.user.expiry_at ?? user?.expiry_at ?? null;
  const whatsappNumber = sub?.whatsapp_number ?? "";

  const handleLogout = () => {
    logout();
    navigate("/welcome");
  };

  return (
    // AnimatePresence on the root container gives the page a subtle
    // fade-in-from-below on first mount (smooth enter/leave between
    // routes when wrapped by <AnimatePresence> in App.tsx later).
    <motion.div
      initial={{ opacity: 0, y: 12 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -12 }}
      transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1] }}
      // BUG FIX (2026-01) — was `min-h-screen` which let the React
      // tree grow past the viewport and turn the document body into
      // a scroll-container. Replaced with hard 100dvh + overflow:hidden
      // so the home page is strictly stationary; only the inner
      // categories <main> scrolls (and even that is unlikely on
      // landscape phones where 4 cards fit on one line).
      className="relative h-screen w-full overflow-hidden"
      style={{ height: "100dvh" }}
      data-testid="home-page-root"
    >
      <div
        className="absolute inset-0 bg-cover bg-center bg-no-repeat"
        style={{ backgroundImage: "url('/images/nebula-bg.png')" }}
      />
      <div className="absolute inset-0 bg-background/40" />

      <div className="relative z-10 h-full flex flex-col min-h-0">
        {/* ────────────────────────── HEADER ────────────────────────── */}
        <FocusableSection
          focusKey="home-header"
          as="header"
          className="flex items-center justify-between px-4 sm:px-6 md:px-8 pt-4 sm:pt-6 gap-2"
        >
          <div className="w-11 h-11 sm:w-14 sm:h-14 rounded-xl glass overflow-hidden flex items-center justify-center shrink-0">
            <Tv className="w-5 h-5 text-muted-foreground" />
          </div>

          <motion.h1
            initial={{ opacity: 0, y: -20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.8 }}
            className="font-display text-xl sm:text-2xl md:text-3xl lg:text-4xl tracking-[0.25em] sm:tracking-[0.3em] gold-text flex-1 text-center truncate"
          >
            NADIPLAYER
          </motion.h1>

          <div className="flex items-center gap-2 sm:gap-3 shrink-0">
            <HeaderClock testId="index-header-clock" />
            <LanguageSelect align="right" />
            <HeaderMenu testId="index-header-menu" />

            {/* "+ Add a profile" — available for ALL users (Guest AND Premium).
                Premium subscribers can layer their own private playlists on top
                of any admin-shared profile, instead of being stuck without an
                add option. */}
            <FocusableButton
              focusKey="home-header-add"
              data-testid="index-add-server-btn"
              onEnter={() => setShowAddServer(true)}
              onClick={() => setShowAddServer(true)}
              className="w-10 h-10 sm:w-11 sm:h-11 rounded-full glass flex items-center justify-center hover:border-primary/40 transition-colors outline-none"
            >
              <Plus className="w-5 h-5 text-muted-foreground" />
            </FocusableButton>

            {!isPaidUser && (
              <FocusableButton
                focusKey="home-header-settings"
                data-testid="index-settings-btn"
                onEnter={() => navigate("/account")}
                onClick={() => navigate("/account")}
                className="hidden sm:flex w-10 h-10 sm:w-11 sm:h-11 rounded-full glass items-center justify-center hover:border-primary/40 transition-colors outline-none"
              >
                <Settings className="w-5 h-5 text-muted-foreground" />
              </FocusableButton>
            )}

            {isPaidUser ? (
              <FocusableButton
                focusKey="home-header-logout"
                data-testid="index-logout-btn"
                onEnter={handleLogout}
                onClick={handleLogout}
                className="flex items-center gap-2 px-3 sm:px-4 h-10 sm:h-11 rounded-full glass text-muted-foreground hover:text-foreground hover:border-primary/40 transition-colors text-[10px] sm:text-xs tracking-[0.2em] uppercase outline-none"
              >
                <LogOut className="w-4 h-4" />
                <span className="hidden sm:inline">{t("home.logout")}</span>
              </FocusableButton>
            ) : (
              <FocusableButton
                focusKey="home-header-profile"
                data-testid="index-profile-btn"
                onEnter={() => navigate("/welcome")}
                onClick={() => navigate("/welcome")}
                className="w-10 h-10 sm:w-11 sm:h-11 rounded-full border-2 border-primary/50 overflow-hidden glass flex items-center justify-center outline-none"
              >
                <User className="w-5 h-5 text-muted-foreground" />
              </FocusableButton>
            )}
          </div>
        </FocusableSection>

        {/* Subscription strip (paid users) OR profile indicator (guests) */}
        {isPaidUser ? (
          <div
            data-testid="subscription-strip"
            className="mx-4 sm:mx-6 md:mx-8 mt-4 glass-card rounded-xl px-4 sm:px-5 py-3 flex flex-wrap items-center justify-between gap-3"
          >
            <div className="flex items-center gap-3 min-w-0">
              <ShieldCheck className="w-5 h-5 text-primary gold-glow shrink-0" />
              <div className="min-w-0">
                <p className="text-foreground text-sm font-medium truncate">
                  {user?.username}
                  <span className="ms-2 text-muted-foreground text-xs">· {t("home.subscriber")}</span>
                </p>
                <p className="text-[10px] sm:text-[11px] tracking-[0.12em] sm:tracking-[0.15em] uppercase text-muted-foreground">
                  {expiryDate ? (
                    <>
                      {t("home.expires")}{" "}
                      <span className="text-foreground">
                        {new Date(expiryDate).toLocaleDateString()}
                      </span>
                    </>
                  ) : (
                    t("home.noExpiry")
                  )}
                </p>
              </div>
            </div>
            <div className="flex items-center gap-3">
              <span
                className={`px-3 py-1.5 rounded-full text-[11px] sm:text-xs font-medium tracking-wider ${
                  isExpired
                    ? "bg-destructive/20 text-destructive border border-destructive/40"
                    : daysRemaining != null && daysRemaining <= 3
                      ? "bg-amber-500/20 text-amber-400 border border-amber-500/40"
                      : "bg-primary/15 text-primary border border-primary/40"
                }`}
              >
                {isExpired
                  ? t("home.expired")
                  : daysRemaining != null
                    ? t("home.daysRemaining", { count: daysRemaining })
                    : ""}
              </span>
            </div>
          </div>
        ) : (
          activeProfile && (
            <div className="text-center mt-2">
              <span className="text-muted-foreground text-xs">
                {t("home.profile")}:{" "}
                <span className="text-primary">{activeProfile.name}</span>
              </span>
            </div>
          )
        )}

        {isGuest && !user && (
          <div className="text-center mt-2">
            <span className="text-muted-foreground text-[10px] sm:text-[11px] tracking-[0.3em] uppercase">
              {t("home.guestMode")}
            </span>
          </div>
        )}

        {/* ─────────────── MAIN — Spatial-navigable row ───────────────
            BUG FIX (2026-01) — was `pb-20 sm:pb-12 pt-4` which carved
            a huge dead-zone at the bottom on landscape phones. Now
            the main shrinks naturally; PageLayout's CSS variable
            already reserves the AdMob / TVBanner bottom strip. */}
        <main className="flex-1 min-h-0 flex items-center justify-center px-2 sm:px-4 pt-3 pb-3 overflow-y-auto"
              style={{ paddingBottom: "calc(env(safe-area-inset-bottom, 0px) + var(--ad-banner-bottom-h, 0px) + var(--tv-banner-h, 0px) + 8px)" }}>
          <FocusableSection
            autoFocus
            focusKey="home-categories"
            className="flex flex-wrap items-center justify-center gap-3 sm:gap-4 md:gap-6 w-full max-w-4xl"
            data-testid="home-categories-row"
          >
            {categoriesConfig.map((cat, i) => (
              <CategoryCard
                key={cat.key}
                title={t(`home.categories.${cat.key}` as const)}
                count={t(`home.categories.${cat.key}Count` as const)}
                icon={cat.icon}
                index={i}
                route={cat.route}
              />
            ))}
          </FocusableSection>
        </main>
      </div>

      {/* AddServerDialog — available for ALL users (Guest AND Premium). */}
      <AddServerDialog
        open={showAddServer}
        onClose={() => setShowAddServer(false)}
        onSubmit={async (data) => {
          const created = await connect(data);
          if (created) setShowAddServer(false);
        }}
      />

      {isPaidUser && isExpired && (
        <ExpiredOverlay
          username={user?.username || "subscriber"}
          whatsappNumber={whatsappNumber}
          onLogout={handleLogout}
        />
      )}
    </motion.div>
  );
};

export default Index;
