import { Link } from '@inertiajs/react';
import { Tv } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';

import { Button } from '@/components/ui/button';
import { useTranslation } from '@/contexts/LanguageContext';
import type { GameSummary } from '@/types/games';

interface Props {
    games: GameSummary[];
}

/**
 * Arcade TV brand color — a vivid indigo that lives between the existing
 * Flash red (#e3232c) and Featured red (#d60000) banner colors. Used as
 * the on-button text color to anchor the band's identity.
 */
const ARCADE_TV_COLOR = '#4338ca';

/**
 * Banner backdrop — a layered gradient that sweeps from a deep indigo
 * (left) through the brand indigo into a violet/fuchsia accent (right),
 * with a soft radial glow over the right side so the marquee gets a
 * natural pool of light.
 */
const ARCADE_TV_GRADIENT = [
    'radial-gradient(circle at 82% 50%, rgba(192, 132, 252, 0.35) 0%, transparent 55%)',
    'linear-gradient(120deg, #1e1b4b 0%, #4338ca 45%, #7e22ce 100%)',
].join(', ');

/**
 * Home-page promo banner for the Arcade TV experience. The marquee track
 * sits BEHIND the text content and spans the full section width, so the
 * cards peek through both halves of the banner. A dark scrim from the
 * left side keeps the headline and CTA legible on top of the moving
 * thumbnails.
 *
 * Rendered between the Flash Games strip and the Tournaments section
 * in default Home.tsx, gated by the `arcadeTvEnabled` prop (driven by
 * `Plugin::hasActive('arcade-tv')` in HomeController).
 */
export default function ArcadeTvBanner({ games }: Props) {
    const { t } = useTranslation();

    return (
        <section
            className="relative my-6 min-h-[320px] overflow-hidden rounded-2xl border shadow-sm sm:min-h-[340px]"
            style={{ background: ARCADE_TV_GRADIENT, color: '#fff' }}
        >
            {/* CRT scanline overlay — faint horizontal stripes for the
                "TV" register. */}
            <div
                className="pointer-events-none absolute inset-0 z-0 mix-blend-overlay"
                style={{
                    backgroundImage:
                        'repeating-linear-gradient(0deg, rgba(255,255,255,0.05) 0px, rgba(255,255,255,0.05) 1px, transparent 1px, transparent 3px)',
                }}
                aria-hidden
            />
            {/* Dot-grid texture for tactile depth. */}
            <div
                className="pointer-events-none absolute inset-0 z-0 opacity-[0.08]"
                style={{
                    backgroundImage:
                        'radial-gradient(circle at 1px 1px, #fff 1px, transparent 0)',
                    backgroundSize: '14px 14px',
                }}
                aria-hidden
            />
            {/* Decorative blurred orb in the bottom-left for asymmetric weight. */}
            <div
                className="pointer-events-none absolute -bottom-16 -start-12 z-0 size-48 rounded-full blur-3xl"
                style={{ background: 'rgba(168, 85, 247, 0.45)' }}
                aria-hidden
            />

            {/* Full-width marquee layer — sits BEHIND the text. Cards are
                taller than the band so they peek through, with the top
                portion of each card clipped by the section's overflow. */}
            <div className="pointer-events-none absolute inset-0 z-10">
                <ArcadeTvMarquee games={games} />
            </div>

            {/* Scrim covering the text area so the headline + CTA stay
                legible over the moving cards. Holds higher opacity for
                ~70% of the width (matching the text container) before
                fading away to let the cards take over the right edge. */}
            <div
                className="pointer-events-none absolute inset-0 z-20"
                style={{
                    background:
                        'linear-gradient(to right, rgba(15,12,45,0.9) 0%, rgba(30,27,75,0.78) 60%, rgba(67,56,202,0.25) 88%, transparent 100%)',
                }}
                aria-hidden
            />

            {/* Foreground content — heading, subhead, CTA. Sized larger
                and given a wider container since the marquee fills the
                rest of the banner — this is the only text in the top layer. */}
            <div className="relative z-30 p-6 sm:p-8 md:max-w-[78%] md:py-10">
                <span className="inline-flex items-center gap-2 text-xs font-bold uppercase tracking-[0.22em] text-cyan-200 sm:text-sm">
                    <Tv className="size-4 shrink-0 text-cyan-300 drop-shadow-[0_0_8px_rgba(103,232,249,0.7)] sm:size-[18px]" />
                    {t('Arcade TV')}
                </span>
                <h2
                    className="mt-3 text-3xl font-extrabold leading-tight sm:text-4xl md:text-5xl"
                    style={{ fontFamily: 'var(--font-display)' }}
                >
                    {t('Play on the big screen')}
                </h2>
                <p className="mt-3 max-w-2xl text-base leading-relaxed opacity-95 sm:text-lg">
                    {t('Play games on your TV\'s browser with your phone as a single-player controller. Or gather friends for multiplayer nights with select titles — up to 8 players in the same room, no extra hardware needed.')}
                </p>
                <div className="mt-5">
                    <Button
                        asChild
                        size="lg"
                        className="h-12 px-6 text-base font-extrabold bg-white hover:bg-white/90 [a]:hover:bg-white/90 shrink-0 shadow-lg shadow-black/20"
                        style={{ color: ARCADE_TV_COLOR }}
                    >
                        <Link href="/tv">{t('Open Arcade TV')}</Link>
                    </Button>
                </div>
            </div>
        </section>
    );
}

/**
 * Horizontal marquee of TV-flagged game thumbnails styled as a row of
 * tilted, oversized cards that peek through the band. The track contains
 * the catalog twice and translates from 0 to -50% so it loops seamlessly.
 * Pause-on-hover is disabled because the layer is `pointer-events-none`
 * (cards aren't clickable — the Start Playing CTA owns interaction).
 *
 * Renders nothing when no games are available; the banner still works on
 * the strength of the headline + CTA alone.
 */
function ArcadeTvMarquee({ games }: { games: GameSummary[] }) {
    const reducedMotion = useReducedMotion();
    const tiles = pickTiles(games, 10);
    // Random rotation/y-offset/peek-depth per tile, generated once per
    // mount and reused for the duplicated set so both halves of the
    // marquee remain identical (preserving the seamless loop). Random
    // values stay stable across re-renders within a single mount.
    const variations = useTileVariations(tiles.length);
    if (tiles.length === 0) return null;

    // Pixel step between card lefts. Cards are 180px wide, step is 155px,
    // so each new card overlaps the previous by 25px — enough to read as
    // "stacked" without crowding the row.
    const STEP = 155;
    // Duplicate so the marquee loops seamlessly — the second set lands
    // exactly where the first set started after a -50% translate.
    const trackTiles = [...tiles, ...tiles];
    const trackWidth = trackTiles.length * STEP;

    return (
        <div
            className="relative h-full w-full overflow-hidden"
            // Soft horizontal mask so the cards melt into the gradient at
            // both the left edge (behind the text) and the right edge.
            style={{
                WebkitMaskImage:
                    'linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%)',
                maskImage:
                    'linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%)',
            }}
        >
            <div
                className="animate-arcade-tv-marquee absolute inset-y-0 start-0"
                style={{ width: `${trackWidth}px` }}
            >
                {trackTiles.map((tile, i) => {
                    const idxInSet = i % tiles.length;
                    const v = variations[idxInSet];
                    return (
                        <div
                            key={i}
                            className="absolute"
                            style={{
                                left: `${i * STEP}px`,
                                // Anchor by `bottom` so cards always sit relative
                                // to the section's bottom edge regardless of how
                                // tall the foreground text grows. Cards (280px
                                // tall) stick ~56px below the section by default,
                                // ±10px of random jitter per card.
                                bottom: `${-56 - v.yOffset}px`,
                                transform: `rotate(${v.rotate}deg)`,
                                zIndex: i + 1,
                            }}
                        >
                            <Tile tile={tile} reducedMotion={reducedMotion} />
                        </div>
                    );
                })}
            </div>
        </div>
    );
}

function Tile({
    tile,
    reducedMotion,
}: {
    tile: GameSummary | null;
    reducedMotion: boolean;
}) {
    const className =
        'block h-[280px] w-[180px] overflow-hidden rounded-xl ring-2 ring-white/15 shadow-2xl shadow-black/50';

    if (!tile) {
        return (
            <div
                className={`${className} flex items-center justify-center bg-black/30 text-white/30`}
                aria-hidden
            >
                <Tv className="size-8" />
            </div>
        );
    }

    // Prefer the upstream-provided animated preview when available — falls
    // back to the static thumbnail when the game ships without one or the
    // user prefers reduced motion.
    const showVideo = !reducedMotion && !!tile.preview_video && !!tile.thumbnail;

    return (
        <div className={className} title={tile.title}>
            {showVideo ? (
                <video
                    src={tile.preview_video!}
                    poster={tile.thumbnail!}
                    autoPlay
                    loop
                    muted
                    playsInline
                    preload="metadata"
                    aria-hidden
                    className="h-full w-full object-cover"
                />
            ) : tile.thumbnail ? (
                <img
                    src={tile.thumbnail}
                    alt=""
                    className="h-full w-full object-cover"
                    loading="lazy"
                    draggable={false}
                />
            ) : (
                <div className="flex h-full w-full items-center justify-center bg-black/30 text-white/40">
                    <Tv className="size-8" />
                </div>
            )}
        </div>
    );
}

/**
 * Generate a random rotation + y-offset per unique tile slot, stable for
 * the lifetime of the component mount. Returned as an array so the
 * marquee's duplicated set can index into the same values (`i % len`)
 * and preserve the seamless loop. Re-runs only when `count` changes,
 * so a server-side game shuffle that swaps catalog entries but keeps
 * the same length doesn't disturb the visual rhythm.
 */
// Deterministic, pure pseudo-random in [0,1) from an integer seed — stable across renders.
function seededRand(seed: number): number {
    const x = Math.sin(seed * 12.9898) * 43758.5453;
    return x - Math.floor(x);
}

function useTileVariations(count: number): { rotate: number; yOffset: number }[] {
    return useMemo(() => {
        return Array.from({ length: count }, (_, i) => ({
            rotate: -10 + seededRand(i + 1) * 20, // -10°…+10°
            yOffset: seededRand(i + 101) * 20, // 0–20px additional peek
        }));
    }, [count]);
}

/**
 * Subscribes to `prefers-reduced-motion` so the marquee tiles can fall
 * back to static thumbnails for users who opt out of motion. Mirrors the
 * pattern used in HoverPreviewVideo.
 */
function useReducedMotion(): boolean {
    const [reduced, setReduced] = useState(false);
    useEffect(() => {
        if (typeof window === 'undefined' || !window.matchMedia) return;
        const m = window.matchMedia('(prefers-reduced-motion: reduce)');
        const update = () => setReduced(m.matches);
        update();
        m.addEventListener('change', update);
        return () => m.removeEventListener('change', update);
    }, []);
    return reduced;
}

/**
 * Use only real games — never pad with duplicates. The marquee adds its
 * own duplicate set for the seamless loop, so padding here would cause
 * the same thumbnail to appear too close to itself in the visible window.
 * Returns an empty array when zero games are available — the caller then
 * renders nothing (banner still has headline + CTA).
 */
function pickTiles(games: GameSummary[], max: number): GameSummary[] {
    return games.slice(0, max);
}
