import { useRef, useState, useEffect, useCallback, RefObject } from 'react';
import { IMedia } from '../types';

interface UseAdjacentCardWidthProps {
  /** Ref to the container whose dimensions constrain the card width. */
  containerRef: RefObject<HTMLDivElement>;
  nextPost: IMedia | null;
  prevPost: IMedia | null;
  /**
   * The settled card width from useMediaCardWidth (updated after the post changes
   * and the new image loads). Used to clear pendingCardWidth once the real width is ready.
   */
  currentCardWidth: string;
  handleNextPost: () => void;
  handlePreviousPost: () => void;
  /** Maximum fraction of the container width (0–1). Defaults to 0.8, matching useMediaCardWidth. */
  maxWidthRatio?: number;
}

interface UseAdjacentCardWidthResult {
  /**
   * Width value to apply to the card immediately on click, before the new post's image
   * has loaded, so the CSS resize transition starts right away instead of after load.
   * Clears automatically once `currentCardWidth` settles to the real value.
   */
  pendingCardWidth: string | null;
  /** Wrapper: sets pendingCardWidth for the next post, then calls handleNextPost. */
  handleNextWithWidth: () => void;
  /** Wrapper: sets pendingCardWidth for the previous post, then calls handlePreviousPost. */
  handlePrevWithWidth: () => void;
}

/**
 * Pre-computes card widths for adjacent posts so the card resize animation starts
 * immediately when an arrow is clicked (instead of after the new image finishes loading).
 *
 * Works alongside useMediaCardWidth: that hook drives the authoritative `currentCardWidth`.
 * This hook only provides a `pendingCardWidth` that bridges the gap between the click
 * and the moment the real image loads.
 */
const useAdjacentCardWidth = ({
  containerRef,
  nextPost,
  prevPost,
  currentCardWidth,
  handleNextPost,
  handlePreviousPost,
  maxWidthRatio = 0.8,
}: UseAdjacentCardWidthProps): UseAdjacentCardWidthResult => {
  const precomputedWidthsRef = useRef<Map<string, string>>(new Map());
  const [pendingCardWidth, setPendingCardWidth] = useState<string | null>(null);

  const precomputeWidth = useCallback(
    (targetPost: IMedia | null) => {
      if (!targetPost || !containerRef.current) return;
      const imageUrl = targetPost.image || targetPost.thumbnail;
      if (!imageUrl) return;

      const container = containerRef.current;
      const img = new window.Image();

      img.onload = () => {
        const containerH = container.clientHeight;
        const containerW = container.clientWidth;
        if (!containerH || !containerW || !img.naturalWidth || !img.naturalHeight) {
          precomputedWidthsRef.current.set(targetPost.id, 'auto');
          return;
        }
        const ratio = img.naturalWidth / img.naturalHeight;
        const naturalWidth = containerH * ratio;
        const maxWidth = containerW * maxWidthRatio;
        precomputedWidthsRef.current.set(
          targetPost.id,
          `${Math.round(Math.min(naturalWidth, maxWidth))}px`,
        );
      };

      img.onerror = () => {
        precomputedWidthsRef.current.set(targetPost.id, 'auto');
      };

      img.src = imageUrl;
    },
    [containerRef, maxWidthRatio],
  );

  // Pre-load widths whenever the adjacent posts change.
  useEffect(() => {
    precomputeWidth(nextPost);
    precomputeWidth(prevPost);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [nextPost?.id, prevPost?.id]);

  // Once useMediaCardWidth settles on the real width, clear the pending override.
  useEffect(() => {
    setPendingCardWidth(null);
  }, [currentCardWidth]);

  const handleNextWithWidth = useCallback(() => {
    if (nextPost) {
      const w = precomputedWidthsRef.current.get(nextPost.id);
      if (w) setPendingCardWidth(w);
    }
    handleNextPost();
  }, [nextPost, handleNextPost]);

  const handlePrevWithWidth = useCallback(() => {
    if (prevPost) {
      const w = precomputedWidthsRef.current.get(prevPost.id);
      if (w) setPendingCardWidth(w);
    }
    handlePreviousPost();
  }, [prevPost, handlePreviousPost]);

  return { pendingCardWidth, handleNextWithWidth, handlePrevWithWidth };
};

export default useAdjacentCardWidth;
