import React, { useEffect, useMemo, useRef, useState } from 'react';

import styles from './RotatedImage.module.css';

type Mode = 'cover' | 'contain';

type RotatedImageProps = {
  url: string;
  rotationDeg: 0 | 90 | 180 | 270;
  mode: Mode;
  alt?: string;
  loading?: React.ImgHTMLAttributes<HTMLImageElement>['loading'];
  decoding?: React.ImgHTMLAttributes<HTMLImageElement>['decoding'];
  /** Высота/ширина полностью контролируются родителем. */
  style?: React.CSSProperties;
  /** Прямоугольник видимого контента (contain/cover) внутри контейнера. */
  onContentRectChange?: ((rect: { x: number; y: number; w: number; h: number }) => void) | undefined;
};

function useElementSize<T extends HTMLElement>() {
  const ref = useRef<T | null>(null);
  const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      const r = el.getBoundingClientRect();
      setSize({ w: r.width, h: r.height });
    });
    ro.observe(el);
    const r = el.getBoundingClientRect();
    setSize({ w: r.width, h: r.height });
    return () => ro.disconnect();
  }, []);

  return [ref, size] as const;
}

export function RotatedImage({
  url,
  rotationDeg,
  mode,
  alt = '',
  loading,
  decoding,
  style,
  onContentRectChange,
}: RotatedImageProps) {
  const [ref, size] = useElementSize<HTMLDivElement>();
  const [imgSize, setImgSize] = useState<{ w: number; h: number } | null>(null);

  useEffect(() => {
    let cancelled = false;
    const img = new Image();
    img.onload = () => {
      if (cancelled) return;
      setImgSize({ w: img.naturalWidth || 1, h: img.naturalHeight || 1 });
    };
    img.src = url;
    return () => {
      cancelled = true;
    };
  }, [url]);

  const scale = useMemo(() => {
    if (!imgSize) return 1;
    if (size.w <= 1 || size.h <= 1) return 1;
    const rotated = rotationDeg === 90 || rotationDeg === 270;
    const iw = rotated ? imgSize.h : imgSize.w;
    const ih = rotated ? imgSize.w : imgSize.h;
    const sx = size.w / iw;
    const sy = size.h / ih;
    return mode === 'cover' ? Math.max(sx, sy) : Math.min(sx, sy);
  }, [imgSize, mode, rotationDeg, size.h, size.w]);

  useEffect(() => {
    if (!onContentRectChange) return;
    if (!imgSize) return;
    if (size.w <= 1 || size.h <= 1) return;
    const rotated = rotationDeg === 90 || rotationDeg === 270;
    // Bounding-box размеров после rotate(): при 90/270 меняются местами.
    const bw = (rotated ? imgSize.h : imgSize.w) * scale;
    const bh = (rotated ? imgSize.w : imgSize.h) * scale;
    const x = (size.w - bw) / 2;
    const y = (size.h - bh) / 2;
    onContentRectChange({ x, y, w: bw, h: bh });
  }, [imgSize, mode, onContentRectChange, rotationDeg, scale, size.h, size.w]);

  const w = imgSize ? imgSize.w * scale : undefined;
  const h = imgSize ? imgSize.h * scale : undefined;

  return (
    <div ref={ref} className={styles.root} style={style}>
      <img
        alt={alt}
        src={url}
        loading={loading}
        decoding={decoding}
        className={styles.img}
        style={{
          width: w ?? '100%',
          height: h ?? '100%',
          objectFit: imgSize ? undefined : mode,
          transform: `translate(-50%, -50%) rotate(${String(rotationDeg)}deg)`,
        }}
      />
    </div>
  );
}
