'use client';

import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import type { PointerEvent } from 'react';

type PreviewState = {
  left: number;
  top: number;
  width: number;
  height: number;
};

function parseRatio(aspectRatio?: string) {
  if (!aspectRatio || aspectRatio === 'long') return aspectRatio === 'long' ? 1 / 3 : 1;
  const [w, h] = aspectRatio.includes('/')
    ? aspectRatio.split('/').map(part => Number(part.trim()))
    : aspectRatio.split(':').map(Number);
  return w && h ? w / h : 1;
}

function nextPreviewState(event: PointerEvent<HTMLElement>, aspectRatio?: string): PreviewState {
  const gap = 12;
  const margin = 10;
  const ratio = parseRatio(aspectRatio);
  const maxWidth = ratio < 0.8 ? 340 : ratio > 1.35 ? 520 : 420;
  const maxHeight = Math.min(window.innerHeight * 0.68, window.innerHeight - margin * 2);
  let width = Math.min(maxWidth, Math.max(240, window.innerWidth * 0.28));
  let height = width / ratio;

  if (height > maxHeight) {
    height = maxHeight;
    width = height * ratio;
  }

  const canOpenRight = event.clientX + gap + width <= window.innerWidth - margin;
  const canOpenLeft = event.clientX - gap - width >= margin;
  let left = canOpenRight || !canOpenLeft
    ? event.clientX + gap
    : event.clientX - width - gap;

  const canOpenBelow = event.clientY + gap + height <= window.innerHeight - margin;
  const canOpenAbove = event.clientY - gap - height >= margin;
  let top = canOpenBelow || !canOpenAbove
    ? event.clientY + gap
    : event.clientY - height - gap;

  if (left + width > window.innerWidth - margin) {
    left = window.innerWidth - width - margin;
  }
  if (top + height > window.innerHeight - margin) {
    top = window.innerHeight - height - margin;
  }
  return {
    left: Math.max(margin, left),
    top: Math.max(margin, top),
    width,
    height,
  };
}

export function HoverImagePreview({
  src,
  alt,
  imageClassName,
  aspectRatio,
  onImageLoad,
}: {
  src: string;
  alt: string;
  imageClassName?: string;
  aspectRatio?: string;
  onImageLoad?: (image: HTMLImageElement) => void;
}) {
  const [preview, setPreview] = useState<PreviewState | null>(null);
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  return (
    <>
      <img
        src={src}
        alt={alt}
        className={imageClassName}
        onPointerMove={event => {
          if (event.pointerType === 'touch') return;
          setPreview(nextPreviewState(event, aspectRatio));
        }}
        onPointerLeave={() => setPreview(null)}
        onLoad={event => onImageLoad?.(event.currentTarget)}
      />
      {preview && mounted && createPortal(
        <div
          className="pointer-events-none fixed z-[90] overflow-hidden rounded-[8px] bg-white shadow-[0_24px_80px_-24px_rgba(0,0,0,0.86)] ring-1 ring-white/20"
          style={{ left: preview.left, top: preview.top, width: preview.width, height: preview.height }}
        >
          <img
            src={src}
            alt=""
            className="h-full w-full object-contain"
          />
        </div>,
        document.body
      )}
    </>
  );
}
