/**
 * DOM утилиты
 */

/**
 * Ожидание загрузки DOM
 */
export function ready(callback) {
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', callback);
  } else {
    callback();
  }
}

/**
 * Создание элемента с атрибутами
 */
export function createElement(tag, attributes = {}, children = []) {
  const element = document.createElement(tag);
  
  // Устанавливаем атрибуты
  Object.entries(attributes).forEach(([key, value]) => {
    if (key === 'className') {
      element.className = value;
    } else if (key === 'dataset') {
      Object.entries(value).forEach(([dataKey, dataValue]) => {
        element.dataset[dataKey] = dataValue;
      });
    } else {
      element.setAttribute(key, value);
    }
  });
  
  // Добавляем детей
  children.forEach(child => {
    if (typeof child === 'string') {
      element.appendChild(document.createTextNode(child));
    } else if (child instanceof Node) {
      element.appendChild(child);
    }
  });
  
  return element;
}

/**
 * Получение ближайшего родителя с селектором
 */
export function closest(element, selector) {
  return element.closest(selector);
}

/**
 * Проверка соответствия элемента селектору
 */
export function matches(element, selector) {
  return element.matches(selector);
}

/**
 * Получение всех родителей элемента
 */
export function parents(element, selector = null) {
  const result = [];
  let current = element.parentElement;
  
  while (current) {
    if (!selector || matches(current, selector)) {
      result.push(current);
    }
    current = current.parentElement;
  }
  
  return result;
}

/**
 * Получение siblings элемента
 */
export function siblings(element, selector = null) {
  const result = [];
  const parent = element.parentElement;
  
  if (!parent) return result;
  
  Array.from(parent.children).forEach(child => {
    if (child !== element && (!selector || matches(child, selector))) {
      result.push(child);
    }
  });
  
  return result;
}

/**
 * Получение размеров элемента
 */
export function getElementSize(element) {
  const rect = element.getBoundingClientRect();
  const computedStyle = window.getComputedStyle(element);
  
  return {
    width: rect.width,
    height: rect.height,
    innerWidth: element.clientWidth,
    innerHeight: element.clientHeight,
    outerWidth: element.offsetWidth,
    outerHeight: element.offsetHeight,
    marginTop: parseFloat(computedStyle.marginTop),
    marginRight: parseFloat(computedStyle.marginRight),
    marginBottom: parseFloat(computedStyle.marginBottom),
    marginLeft: parseFloat(computedStyle.marginLeft),
    paddingTop: parseFloat(computedStyle.paddingTop),
    paddingRight: parseFloat(computedStyle.paddingRight),
    paddingBottom: parseFloat(computedStyle.paddingBottom),
    paddingLeft: parseFloat(computedStyle.paddingLeft)
  };
}

/**
 * Получение позиции элемента
 */
export function getElementPosition(element) {
  const rect = element.getBoundingClientRect();
  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  
  return {
    top: rect.top + scrollTop,
    left: rect.left + scrollLeft,
    right: rect.right + scrollLeft,
    bottom: rect.bottom + scrollTop,
    x: rect.left + scrollLeft,
    y: rect.top + scrollTop,
    viewportTop: rect.top,
    viewportLeft: rect.left,
    viewportRight: rect.right,
    viewportBottom: rect.bottom
  };
}

/**
 * Проверка видимости элемента
 */
export function isVisible(element) {
  const style = window.getComputedStyle(element);
  return style.display !== 'none' && 
         style.visibility !== 'hidden' && 
         style.opacity !== '0';
}

/**
 * Проверка нахождения элемента в viewport
 */
export function isInViewport(element, offset = 0) {
  const rect = element.getBoundingClientRect();
  const windowHeight = window.innerHeight || document.documentElement.clientHeight;
  const windowWidth = window.innerWidth || document.documentElement.clientWidth;
  
  return rect.top >= -offset &&
         rect.left >= -offset &&
         rect.bottom <= windowHeight + offset &&
         rect.right <= windowWidth + offset;
}

/**
 * Плавная прокрутка к элементу
 */
export function scrollToElement(element, options = {}) {
  const defaults = {
    behavior: 'smooth',
    block: 'start',
    inline: 'nearest',
    offset: 0
  };
  
  const config = { ...defaults, ...options };
  
  if (config.offset) {
    const elementPosition = getElementPosition(element);
    window.scrollTo({
      top: elementPosition.top - config.offset,
      behavior: config.behavior
    });
  } else {
    element.scrollIntoView({
      behavior: config.behavior,
      block: config.block,
      inline: config.inline
    });
  }
}

/**
 * Добавление CSS стилей
 */
export function setStyle(element, styles) {
  Object.entries(styles).forEach(([property, value]) => {
    element.style[property] = value;
  });
}

/**
 * Получение вычисленного стиля
 */
export function getStyle(element, property) {
  return window.getComputedStyle(element)[property];
}

/**
 * Анимация изменения свойств элемента
 */
export function animate(element, properties, duration = 300, easing = 'ease-in-out') {
  return new Promise((resolve) => {
    const startTime = performance.now();
    const initialStyles = {};
    
    // Сохраняем начальные значения
    Object.keys(properties).forEach(prop => {
      initialStyles[prop] = parseFloat(getStyle(element, prop)) || 0;
    });
    
    function step(currentTime) {
      const elapsed = currentTime - startTime;
      const progress = Math.min(elapsed / duration, 1);
      
      // Применяем easing
      const easedProgress = easingFunctions[easing] ? 
        easingFunctions[easing](progress) : progress;
      
      // Обновляем стили
      Object.entries(properties).forEach(([prop, endValue]) => {
        const startValue = initialStyles[prop];
        const currentValue = startValue + (endValue - startValue) * easedProgress;
        element.style[prop] = currentValue + (typeof endValue === 'string' && endValue.includes('px') ? 'px' : '');
      });
      
      if (progress < 1) {
        requestAnimationFrame(step);
      } else {
        resolve();
      }
    }
    
    requestAnimationFrame(step);
  });
}

/**
 * Easing функции
 */
const easingFunctions = {
  'linear': t => t,
  'ease-in': t => t * t,
  'ease-out': t => t * (2 - t),
  'ease-in-out': t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
  'ease-in-cubic': t => t * t * t,
  'ease-out-cubic': t => (--t) * t * t + 1,
  'ease-in-out-cubic': t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
};

/**
 * Делегирование событий
 */
export function delegate(container, selector, event, handler) {
  container.addEventListener(event, (e) => {
    const target = e.target.closest(selector);
    if (target && container.contains(target)) {
      handler.call(target, e, target);
    }
  });
}

/**
 * Однократное выполнение события
 */
export function once(element, event, handler) {
  const onceHandler = (e) => {
    handler(e);
    element.removeEventListener(event, onceHandler);
  };
  element.addEventListener(event, onceHandler);
}

/**
 * Удаление элемента из DOM
 */
export function remove(element) {
  if (element && element.parentNode) {
    element.parentNode.removeChild(element);
  }
}

/**
 * Клонирование элемента
 */
export function clone(element, deep = true) {
  return element.cloneNode(deep);
}

/**
 * Получение текста элемента
 */
export function getText(element) {
  return element.textContent || element.innerText || '';
}

/**
 * Установка текста элемента
 */
export function setText(element, text) {
  element.textContent = text;
}

/**
 * Получение HTML элемента
 */
export function getHTML(element) {
  return element.innerHTML;
}

/**
 * Установка HTML элемента
 */
export function setHTML(element, html) {
  element.innerHTML = html;
}