import { forwardRef, useImperativeHandle } from "react";
import { useFocusable, setFocus } from "@noriginmedia/norigin-spatial-navigation";
import { cn } from "@/lib/utils";
import { playSelectSound, playMoveSound } from "@/lib/navSounds";
import { isSmartTV } from "@/lib/platform";
import { tvScrollIntoView } from "@/lib/tvScrollIntoView";

export type FocusableTileProps = React.HTMLAttributes<HTMLDivElement> & {
  focusKey?: string;
  onEnter?: () => void;
  /** If true, skip the auto scale-on-focus (used by already-transformed tiles). */
  subtle?: boolean;
};

/**
 * A focusable card/tile — used for movies, series, channels, profile cards.
 *
 * Input matrix (auto-detected, no flag needed):
 *   • Tizen / webOS remote arrows + OK    → onFocus / onEnterPress
 *   • Keyboard arrows + Enter             → onFocus / onEnterPress
 *   • Mouse hover                         → onMouseEnter calls setFocus()
 *                                           so the focus ring follows the
 *                                           cursor too. The same focus
 *                                           state drives the visual.
 *   • Mouse click / touch tap             → onClick triggers onEnter
 *
 * The element scrolls itself into view whenever focus lands on it so the
 * gold ring never sits off-screen on TV layouts.
 */
export const FocusableTile = forwardRef<HTMLDivElement, FocusableTileProps>(
  ({ className, focusKey, onClick, onEnter, onMouseEnter, subtle, children, ...rest }, externalRef) => {
    const { ref, focused, focusKey: resolvedFocusKey } = useFocusable({
      focusKey,
      onEnterPress: () => {
        playSelectSound();
        (onEnter ?? onClick)?.(
          { currentTarget: ref.current } as unknown as React.MouseEvent<HTMLDivElement>,
        );
      },
      onFocus: ({ node }) => {
        playMoveSound();
        if (!node) return;
        // BUG FIX (2026-01) — Tizen / webOS "channel list won't auto-
        // scroll on D-pad" (second fix, supersedes the previous
        // behavior-flag tweak).
        //
        // Native `Element.scrollIntoView()` is unreliable on Tizen
        // 4-7 and webOS 4-6: it either silently no-ops or fires
        // against the wrong scrollable ancestor when there are
        // multiple `overflow: auto` containers nested under React's
        // flex tree. We replace it with a manual implementation that
        //   • locates the nearest scrollable ancestor (overflow-y
        //     auto/scroll) with real overflow,
        //   • centres the focused tile inside that ancestor by
        //     writing to `scrollTop` directly.
        //
        // Mobile / web continue to use the native API for the
        // gentler smooth-scroll feel users expect there.
        const tv = isSmartTV();
        if (tv) {
          tvScrollIntoView(node as HTMLElement);
          return;
        }
        try {
          (node as HTMLElement).scrollIntoView({
            behavior: "smooth",
            block: "nearest",
            inline: "nearest",
          });
        } catch {
          try { (node as HTMLElement).scrollIntoView(true); } catch { /* give up */ }
        }
      },
    });

    useImperativeHandle(externalRef, () => ref.current as HTMLDivElement);

    const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
      playSelectSound();
      onClick?.(e);
    };

    const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
      // Promote mouse hover to a focus event so the gold ring + sound
      // behave identically to remote / keyboard navigation.
      if (resolvedFocusKey) setFocus(resolvedFocusKey);
      onMouseEnter?.(e);
    };

    return (
      <div
        ref={ref as unknown as React.Ref<HTMLDivElement>}
        role="button"
        tabIndex={0}
        data-focused={focused || undefined}
        onClick={handleClick}
        onMouseEnter={handleMouseEnter}
        className={cn(
          "focusable",
          !subtle && "focusable-tile",
          focused && "is-focused",
          className,
        )}
        {...rest}
      >
        {children}
      </div>
    );
  },
);
FocusableTile.displayName = "FocusableTile";
