import * as React from 'react';
import {
  useEffect,
  useCallback,
  FC,
  useMemo,
  useRef, useState,
  RefObject,
  CSSProperties,
} from 'react';
import { style } from 'typestyle';
import { useStore } from '../../services/store';
import { overlayZIndex, ugcZIndex } from '../consts';
import { IMedia } from '../../types';
import ShopThisLookProductList from '../ShopThisLook/ProductList';
import ShopThisLookModal from '../ShopThisLook/Modal';
import MobilePlayer from './Player/MobilePlayer';
import DesktopPlayer from './Player/DesktopPlayer';
import { useDialogFocusTrap } from '../../hooks/useDialogFocusTrap';
import useActiveThumbnailRect from '../../hooks/useActiveThumbnailRect';
import ThumbnailPills, { thumbnailPillsHoverClass } from '../ThumbnailPills';
import { usePostViewerEvents } from '../../hooks/usePostViewerEvents';

interface PostViewerProps {
  onPostChange: (post: IMedia | null) => void;
}

const PostViewer: FC<PostViewerProps> = ({ onPostChange }) => {
  const store = useStore();
  const { triggerCloseEvent } = usePostViewerEvents();
  const dialogRef = useRef<HTMLDivElement | null>(null);

  const dialogTitleId = useMemo(
    () => `${store.config.classPrefix || 'adl'}-postviewer-title`,
    [store.config.classPrefix],
  );

  useDialogFocusTrap({ active: Boolean(store.post), containerRef: dialogRef });

  // Event handlers
  const handleClose = useCallback(() => {
    if (store.post) {
      triggerCloseEvent(store.post);
    }
    store.setStoreState((prevState) => ({ ...prevState, post: null }));
    window.history.replaceState(null, '', null);
  }, [store, triggerCloseEvent]);

  // Basic keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') handleClose();
    };
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [handleClose]);

  // (Focus trap handled by useDialogFocusTrap)

  if (!store.post) return null;

  // Determine what to show:
  // - On mobile: use MobilePlayer by default
  // - On desktop with product_list mode + display_desktop_player flag: use DesktopPlayer
  // - On desktop with product_list mode: show the product list component
  // - On mobile when shop_this_look_display is 'modal': show the product list component
  // - Otherwise: show the modal component
  const showMobilePlayer = store.isMobile && (store.data.settings.mobile_player_display !== false);

  const showDesktopPlayer = !showMobilePlayer
    && !store.isMobile
    && store.data.settings.shop_this_look_display === 'product_list'
    && store.data.settings.display_desktop_player === true;

  const showProductList = !showMobilePlayer
    && !showDesktopPlayer
    && (
      store.data.settings.shop_this_look_display === 'product_list'
      || (store.isMobile && store.data.settings.shop_this_look_display === 'modal')
    );

  const renderPlayerComponent = () => {
    if (!store.post) {
      return null;
    }
    if (showMobilePlayer) {
      return (
        <MobilePlayer
          post={store.post}
          settings={store.data.settings}
          totalPosts={store.data.content.medias.length}
          onClose={handleClose}
          onPostChange={onPostChange}
          classPrefix={store.config.classPrefix || ''}
        />
      );
    }
    if (showDesktopPlayer) {
      return (
        <DesktopPlayer
          post={store.post}
          settings={store.data.settings}
          totalPosts={store.data.content.medias.length}
          onClose={handleClose}
          onPostChange={onPostChange}
          classPrefix={store.config.classPrefix || ''}
        />
      );
    }
    if (showProductList) {
      return (
        <ShopThisLookProductList
          post={store.post}
          settings={store.data.settings}
          totalPosts={store.data.content.medias.length}
          onClose={handleClose}
          onPostChange={onPostChange}
          classPrefix={store.config.classPrefix || ''}
        />
      );
    }
    return (
      <ShopThisLookModal
        post={store.post}
        settings={store.data.settings}
        totalPosts={store.data.content.medias.length}
        onClose={handleClose}
        onPostChange={onPostChange}
        classPrefix={store.config.classPrefix || ''}
      />
    );
  };

  return (
    <div>
      <div
        className={`${styles.overlay}  ${store.config.classPrefix}-overlay`}
        onClick={handleClose}
        aria-hidden='true'
      />
      {showProductList && !showMobilePlayer && !showDesktopPlayer ? (
        <ActiveThumbnailHighlight
          key={store.post.id}
          post={store.post}
          classPrefix={store.config.classPrefix || 'adl-wdgt'}
        />
      ) : null}
      <div
        ref={dialogRef}
        role='dialog'
        aria-modal='true'
        aria-labelledby={dialogTitleId}
        tabIndex={-1}
      >
        <h2 id={dialogTitleId} style={styles.srOnly}>
          Post preview
        </h2>
        {renderPlayerComponent()}
      </div>
    </div>
  );
};

/**
 * Renders a fixed-position clone of the active thumbnail in the portal,
 * sitting between the overlay (z-index 999) and the product list (z-index 1003).
 *
 * This solves a stacking context issue: the real thumbnail lives in the widget DOM
 * which may be trapped in a client-page stacking context. By rendering a visual copy
 * at the body level (via the portal), it reliably appears above the overlay.
 *
 * Position and image are synced via direct DOM mutation in a RAF loop (no React
 * state), so the clone moves in the same frame as the carousel.
 */
const ActiveThumbnailHighlight: FC<{ post: IMedia; classPrefix: string }> = ({
  post,
  classPrefix,
}) => {
  const cloneRef = useRef<HTMLDivElement>(null);
  const videoRef = useRef<HTMLVideoElement>(null);
  const [userMutedPreference, setUserMutedPreference] = useState(true);
  const isForceMuted = post.isMuted === true;
  const isMuted = isForceMuted || userMutedPreference;
  useActiveThumbnailRect(cloneRef as RefObject<HTMLElement>, post);

  useEffect(() => {
    // reload the video when the post changes
    if (videoRef.current) {
      videoRef.current.load();
    }
  }, [post.video]);

  useEffect(() => {
    if (videoRef.current) {
      videoRef.current.muted = isMuted;
    }
  }, [isMuted]);

  const showMute = post.type === 'video' && !!post.video;

  return (
    <div
      ref={cloneRef}
      aria-hidden='true'
      // The public active class is on the clone (not the real thumbnail) so
      // any client CSS targeting it applies to the element that is actually
      // visible above the overlay.
      className={
        `${classPrefix}-thumbnail-content-active ${styles.cloneDefaults} 
        ${thumbnailPillsHoverClass}`
      }
      style={{
        display: 'none', // hook takes over immediately on first RAF tick
        position: 'fixed',
        zIndex: ugcZIndex,
        overflow: 'hidden',
      }}
    >
      {post.type === 'video' && post.video ? (
        <video
          ref={videoRef}
          autoPlay
          loop
          muted={isForceMuted ? true : isMuted}
          playsInline
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            width: '100%',
            height: '100%',
            objectFit: 'cover',
          }}
        >
          <source src={post.video} type='video/mp4' />
        </video>
      ) : null}

      <ThumbnailPills
        post={post}
        showMute={showMute && !isForceMuted}
        isMuted={isMuted}
        onMuteToggle={() => setUserMutedPreference((m) => !m)}
        showUsernamePill={!!post.username}
        isMobile={false}
      />
    </div>
  );
};

const styles = {
  cloneDefaults: style({
    backgroundSize: 'cover',
    backgroundPosition: 'center',
  }),
  overlay: style({
    position: 'fixed',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
    zIndex: overlayZIndex,
  }),
  srOnly: {
    position: 'absolute',
    width: 1,
    height: 1,
    padding: 0,
    margin: -1,
    overflow: 'hidden',
    clip: 'rect(0, 0, 0, 0)',
    whiteSpace: 'nowrap',
    border: 0,
  } as CSSProperties,
};

export default PostViewer;
