import React, { Ref, useCallback, useEffect, useLayoutEffect, useRef } from 'react';

import { launchSplash } from '../../plugins/launchSplash';
import { attachMascotVideo, detachMascotVideo, mascotVideoReady } from './mascotSingleton';
import * as css from './styles.css';

type AuthMascotProps = {
  mascotRef?: Ref<HTMLDivElement>;
  // True for the splash-gate variant (cold start, sync wait): mascot is
  // centered both axes to mirror the Android 12+ system splash icon, so the
  // native → WebView → web-splash handoff reads as one continuous splash.
  // False (default) keeps the auth-page positioning (top-anchored) used by
  // login / register / reset-password.
  centered?: boolean;
};

export function AuthMascot({ mascotRef, centered }: AuthMascotProps) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const didSignalLaunchReadyRef = useRef(false);

  // Singleton <video> attach/detach. Preserves currentTime across the
  // ConfigConfigLoading → SpecVersionsLoader → ClientRootLoading remounts
  // so the mascot loop reads as one continuous animation instead of two
  // restarts mid-boot.
  useLayoutEffect(() => {
    const container = containerRef.current;
    if (!container) return undefined;
    attachMascotVideo(container, css.AuthMascotVideo);
    return () => {
      detachMascotVideo(container);
    };
  }, []);

  // Native splash hand-off: only the centered (splash-gate) variant signals
  // the Android system splash to drop. Auth pages (login/register) don't
  // signal — they're already past the cold-boot phase by the time they
  // mount. requestAnimationFrame×2 ensures the browser has actually
  // committed the paint before we ask the OS to release its splash.
  const signalLaunchReady = useCallback(() => {
    if (!centered || didSignalLaunchReadyRef.current) return;
    didSignalLaunchReadyRef.current = true;
    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        launchSplash.ready();
      });
    });
  }, [centered]);

  useEffect(() => {
    if (!centered) return undefined;
    let cancelled = false;
    mascotVideoReady().then(() => {
      if (!cancelled) signalLaunchReady();
    });
    return () => {
      cancelled = true;
    };
  }, [centered, signalLaunchReady]);

  const setRefs = useCallback(
    (node: HTMLDivElement | null) => {
      containerRef.current = node;
      if (typeof mascotRef === 'function') {
        mascotRef(node);
      } else if (mascotRef && typeof mascotRef === 'object') {
        // Forward-ref mutation is the canonical React pattern for combining
        // refs; the eslint rule fires on any param mutation, but a MutableRefObject
        // is specifically designed for this.
        // eslint-disable-next-line no-param-reassign
        (mascotRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
      }
    },
    [mascotRef]
  );

  return (
    <div
      className={centered ? css.AuthMascotCentered : css.AuthMascot}
      aria-hidden="true"
      ref={setRefs}
    />
  );
}
