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';

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

const PostViewer: FC<PostViewerProps> = ({ onPostChange }) => {
  const store = useStore();
  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(() => {
    store.setStoreState((prevState) => ({ ...prevState, post: null }));
    window.history.replaceState(null, '', null);
  }, [store]);

  // 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');

  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>
        {showMobilePlayer ? (
          <MobilePlayer
            post={store.post}
            settings={store.data.settings}
            totalPosts={store.data.content.medias.length}
            onClose={handleClose}
            onPostChange={onPostChange}
            classPrefix={store.config.classPrefix || ''}
          />
        ) : showDesktopPlayer ? (
          <DesktopPlayer
            post={store.post}
            settings={store.data.settings}
            totalPosts={store.data.content.medias.length}
            onClose={handleClose}
            onPostChange={onPostChange}
            classPrefix={store.config.classPrefix || ''}
          />
        ) : showProductList ? (
          <ShopThisLookProductList
            post={store.post}
            settings={store.data.settings}
            totalPosts={store.data.content.medias.length}
            onClose={handleClose}
            onPostChange={onPostChange}
            classPrefix={store.config.classPrefix || ''}
          />
        ) : (
          <ShopThisLookModal
            post={store.post}
            settings={store.data.settings}
            totalPosts={store.data.content.medias.length}
            onClose={handleClose}
            onPostChange={onPostChange}
            classPrefix={store.config.classPrefix || ''}
          />
        )}
      </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 store = useStore();
  const cloneRef = useRef<HTMLDivElement>(null);
  const videoRef = useRef<HTMLVideoElement>(null);
  const [isMuted, setIsMuted] = useState(true);
  useActiveThumbnailRect(cloneRef as RefObject<HTMLElement>, post);

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

  const showMute = post.type === 'video' && !!post.video;
  const showAttribution = store.data.settings.show_attribution ?? true;

  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={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}
        isMuted={isMuted}
        onMuteToggle={() => setIsMuted((m) => !m)}
        showUsername={!!post.username}
        showAttribution={showAttribution}
        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;
