import * as React from 'react';
import {
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';

import { cn } from '@/lib/utils';

interface GridProps extends React.ComponentProps<'div'> {
  /**
   * Направление расположения дочерних элементов
   * @default 'row' - элементы располагаются горизонтально (GridCol)
   */
  direction?: 'row' | 'column';
}

/**
 * Родительский контейнер Grid
 * Занимает все доступное место (100% width и height)
 */
function Grid({
  className,
  style,
  direction = 'row',
  ...props
}: GridProps) {
  return (
    <div
      data-slot="grid"
      className={cn(
        'w-full ',
        direction === 'row' ? 'flex flex-row' : 'flex flex-col',
        className
      )}
      style={{
        ...style,
        // height: `100%`

      }}
      {...props}
    />
  );
}

interface GridColProps extends React.ComponentProps<'div'> {
  /**
   * Ширина колонки
   * Если не указана, колонка занимает равную долю доступного пространства
   * Можно указать в пикселях (например, "200px") или в процентах (например, "30%")
   */
  width?: string | number;
}

/**
 * Колонка Grid
 * Занимает все доступное место вертикально
 * Если несколько колонок - делят равномерно доступное пространство
 * Если указана width - занимает эту ширину, остальные делят оставшееся пространство
 */
function GridCol({
  className,
  width,
  style,
  ...props
}: GridColProps) {
  const baseStyle = width
    ? {
      flexShrink: 0,
      flexGrow: 0,
      width: typeof width === 'number' ? `${width}px` : width,

    }
    : {
      flexGrow: 1,
      flexShrink: 1,
      flexBasis: 0,
      minWidth: 0,

    };

  const flexStyle: React.CSSProperties = {
    ...baseStyle,
    ...style, // Переданный style имеет приоритет, но width из props сохраняется
    ...(width && { width: typeof width === 'number' ? `${width}px` : width }), // width из props имеет приоритет
  };

  return (
    <div
      data-slot="grid-col"
      className={cn(
        'h-full flex flex-col',
        className
      )}
      style={flexStyle}
      {...props}
    />
  );
}

interface GridRowProps extends React.ComponentProps<'div'> {
  /**
   * Высота строки
   * Если не указана, строка занимает равную долю доступного пространства
   * Можно указать в пикселях (например, "200px") или в процентах (например, "30%")
   */
  height?: string | number;
  /**
   * Автоматически подстраивать высоту под контент
   * При включении высота будет определяться размером контента внутри
   * и автоматически обновляться при изменении размера контента
   */
  autoSize?: boolean;
  /**
   * Callback для получения ref элемента строки
   */
  onRef?: (ref: React.RefObject<HTMLDivElement | null>) => void;
}

/**
 * Строка Grid
 * Занимает все доступное место горизонтально
 * Если несколько строк - делят равномерно доступное пространство
 * Если указана height - занимает эту высоту, остальные делят оставшееся пространство
 */
function GridRow({
  className,
  height,
  style,
  autoSize = false,
  children,
  onRef,
  ...props
}: GridRowProps) {
  const rowRef = useRef<HTMLDivElement>(null);
  const [contentHeight, setContentHeight] = useState<number | null>(null);

  // Передаем ref через callback
  useEffect(() => {
    if (onRef) {
      onRef(rowRef);
    }
  }, [onRef]);

  // Функция для обновления высоты на основе контента
  const updateHeight = useCallback(() => {
    if (rowRef.current) {
      // Сохраняем текущую высоту
      const currentHeight = rowRef.current.style.height;
      // Временно сбрасываем высоту для точного измерения контента
      rowRef.current.style.height = 'auto';
      // Измеряем реальную высоту контента
      const scrollHeight = rowRef.current.scrollHeight;
      // Восстанавливаем высоту (или устанавливаем новую)
      rowRef.current.style.height = currentHeight;
      // Обновляем состояние только если высота изменилась
      setContentHeight((prev) => {
        if (prev !== scrollHeight) {
          return scrollHeight;
        }
        return prev;
      });
    }
  }, []);

  useEffect(() => {
    if (!autoSize) {
      setContentHeight(null);
      return;
    }

    if (!rowRef.current) {
      return;
    }

    // Функция для наблюдения за дочерними элементами
    const observeChildren = (resizeObserver: ResizeObserver) => {
      if (rowRef.current) {
        Array.from(rowRef.current.children).forEach((child) => {
          if (child instanceof HTMLElement) {
            resizeObserver.observe(child);
          }
        });
      }
    };

    // Небольшая задержка для первоначального измерения после рендера
    const timeoutId = setTimeout(() => {
      updateHeight();
    }, 0);

    // Используем ResizeObserver если доступен
    if (typeof ResizeObserver !== 'undefined') {
      const resizeObserver = new ResizeObserver(() => {
        // Используем requestAnimationFrame для плавного обновления
        requestAnimationFrame(() => {
          updateHeight();
        });
      });

      // Наблюдаем за изменениями размера самого элемента
      if (rowRef.current) {
        resizeObserver.observe(rowRef.current);
        observeChildren(resizeObserver);
      }

      // MutationObserver для отслеживания добавления/удаления дочерних элементов
      const mutationObserver = new MutationObserver(() => {
        if (rowRef.current) {
          observeChildren(resizeObserver);
          // Обновляем высоту после изменения структуры
          requestAnimationFrame(() => {
            updateHeight();
          });
        }
      });

      if (rowRef.current) {
        mutationObserver.observe(rowRef.current, {
          childList: true,
          subtree: true,
        });
      }

      return () => {
        clearTimeout(timeoutId);
        resizeObserver.disconnect();
        mutationObserver.disconnect();
      };
    } else {
      // Fallback: используем интервал для проверки изменений
      const intervalId = setInterval(() => {
        updateHeight();
      }, 100); // Проверяем каждые 100мс

      return () => {
        clearTimeout(timeoutId);
        clearInterval(intervalId);
      };
    }
  }, [autoSize, children, updateHeight]);

  // Базовый стиль
  const baseStyle = autoSize
    ? {
      flexShrink: 0,
      flexGrow: 0,
      height: contentHeight !== null ? `${contentHeight}px` : 'auto',
      overflow: 'visible', // Позволяем контенту быть видимым
    }
    : height
      ? {
        flexShrink: 0,
        flexGrow: 0,
        height: typeof height === 'number' ? `${height}px` : height
      }
      : {
        flexGrow: 1,
        flexShrink: 1,
        flexBasis: 0,
        minHeight: 0
      };

  const flexStyle: React.CSSProperties = {
    ...baseStyle,
    ...style, // Переданный style имеет приоритет, но height из props сохраняется
    ...(height && !autoSize && { height: typeof height === 'number' ? `${height}px` : height }), // height из props имеет приоритет (только если не autoSize)
    ...(autoSize && contentHeight !== null && { height: `${contentHeight}px` }), // autoSize имеет приоритет
  };

  return (
    <div
      ref={rowRef}
      data-slot="grid-row"
      className={cn(
        'w-full flex flex-row overflow-y-auto',
        className
      )}
      style={flexStyle}
      {...props}
    >
      {children}
    </div>
  );
}

export { Grid, GridCol, GridRow };
