/**
 * Element Effects
 *
 * Types and utilities for UI element animations and interactions.
 * Used by constructor, RuntimePresentation, and element settings pages.
 */

import type { CSSProperties } from 'react';

/**
 * Normalize duration value to include 's' suffix.
 * Accepts: '0.3', '0.3s', '300ms', 0.3
 * Returns: '0.3s' (or original if already has valid unit)
 */
function normalizeDuration(value: string | number | undefined): string {
  if (!value && value !== 0) return '';

  const str = String(value).trim();
  if (!str) return '';

  // Already has 's' or 'ms' suffix - return as is
  if (/^\d*\.?\d+(s|ms)$/i.test(str)) {
    return str;
  }

  // Just a number - append 's'
  const num = parseFloat(str);
  if (Number.isFinite(num)) {
    return `${num}s`;
  }

  return str;
}

/**
 * Appear animation types
 */
export type AppearAnimationType =
  | ''
  | 'fade'
  | 'slide-up'
  | 'slide-down'
  | 'slide-left'
  | 'slide-right'
  | 'scale';

/**
 * Effect properties supported by UI elements.
 * These properties can be set in element defaults and applied at runtime.
 */
export interface ElementEffectProperties {
  // Appear animation
  appearAnimation?: AppearAnimationType;
  appearAnimationDuration?: string;
  appearAnimationEasing?: string;
  // Hover effects
  hoverScale?: string;
  hoverOpacity?: string;
  hoverBackgroundColor?: string;
  hoverColor?: string;
  hoverBoxShadow?: string;
  hoverTransitionDuration?: string;
  // Focus effects
  focusScale?: string;
  focusOpacity?: string;
  focusOutline?: string;
  focusBoxShadow?: string;
  // Active/press effects
  activeScale?: string;
  activeOpacity?: string;
  activeBackgroundColor?: string;
}

/**
 * Array of effect property names for iteration.
 */
export const EFFECT_PROPS = [
  'appearAnimation',
  'appearAnimationDuration',
  'appearAnimationEasing',
  'hoverScale',
  'hoverOpacity',
  'hoverBackgroundColor',
  'hoverColor',
  'hoverBoxShadow',
  'hoverTransitionDuration',
  'focusScale',
  'focusOpacity',
  'focusOutline',
  'focusBoxShadow',
  'activeScale',
  'activeOpacity',
  'activeBackgroundColor',
] as const;

export type EffectPropName = (typeof EFFECT_PROPS)[number];

/**
 * Build base transition style for smooth state changes.
 */
export function buildTransitionStyle(
  effects: Partial<ElementEffectProperties>,
): CSSProperties {
  const duration =
    normalizeDuration(effects.hoverTransitionDuration) || '0.2s';
  return {
    transition: `all ${duration} ease`,
  };
}

/**
 * Build hover state style overrides.
 */
export function buildHoverStyle(
  effects: Partial<ElementEffectProperties>,
): CSSProperties {
  const style: CSSProperties = {};

  if (effects.hoverScale) {
    style.transform = `scale(${effects.hoverScale})`;
  }
  if (effects.hoverOpacity) {
    const parsed = Number(effects.hoverOpacity);
    if (Number.isFinite(parsed)) {
      style.opacity = parsed;
    }
  }
  if (effects.hoverBackgroundColor) {
    style.backgroundColor = effects.hoverBackgroundColor;
  }
  if (effects.hoverColor) {
    style.color = effects.hoverColor;
  }
  if (effects.hoverBoxShadow) {
    style.boxShadow = effects.hoverBoxShadow;
  }

  return style;
}

/**
 * Build focus state style overrides.
 */
export function buildFocusStyle(
  effects: Partial<ElementEffectProperties>,
): CSSProperties {
  const style: CSSProperties = {};

  if (effects.focusScale) {
    style.transform = `scale(${effects.focusScale})`;
  }
  if (effects.focusOpacity) {
    const parsed = Number(effects.focusOpacity);
    if (Number.isFinite(parsed)) {
      style.opacity = parsed;
    }
  }
  if (effects.focusOutline) {
    style.outline = effects.focusOutline;
  }
  if (effects.focusBoxShadow) {
    style.boxShadow = effects.focusBoxShadow;
  }

  return style;
}

/**
 * Build active/press state style overrides.
 */
export function buildActiveStyle(
  effects: Partial<ElementEffectProperties>,
): CSSProperties {
  const style: CSSProperties = {};

  if (effects.activeScale) {
    style.transform = `scale(${effects.activeScale})`;
  }
  if (effects.activeOpacity) {
    const parsed = Number(effects.activeOpacity);
    if (Number.isFinite(parsed)) {
      style.opacity = parsed;
    }
  }
  if (effects.activeBackgroundColor) {
    style.backgroundColor = effects.activeBackgroundColor;
  }

  return style;
}

/**
 * Get CSS keyframes for appear animation.
 */
export function getAppearAnimationKeyframes(
  animationType: AppearAnimationType,
): string {
  switch (animationType) {
    case 'fade':
      return 'element-fade-in';
    case 'slide-up':
      return 'element-slide-up';
    case 'slide-down':
      return 'element-slide-down';
    case 'slide-left':
      return 'element-slide-left';
    case 'slide-right':
      return 'element-slide-right';
    case 'scale':
      return 'element-scale-in';
    default:
      return '';
  }
}

/**
 * Build appear animation style.
 */
export function buildAppearAnimationStyle(
  effects: Partial<ElementEffectProperties>,
): CSSProperties {
  if (!effects.appearAnimation) {
    return {};
  }

  const animationName = getAppearAnimationKeyframes(effects.appearAnimation);
  if (!animationName) {
    return {};
  }

  const duration =
    normalizeDuration(effects.appearAnimationDuration) || '0.3s';
  const easing = effects.appearAnimationEasing || 'ease';

  return {
    animation: `${animationName} ${duration} ${easing} forwards`,
  };
}

/**
 * Check if element has any hover effects configured.
 */
export function hasHoverEffects(
  effects: Partial<ElementEffectProperties>,
): boolean {
  return Boolean(
    effects.hoverScale ||
      effects.hoverOpacity ||
      effects.hoverBackgroundColor ||
      effects.hoverColor ||
      effects.hoverBoxShadow,
  );
}

/**
 * Check if element has any focus effects configured.
 */
export function hasFocusEffects(
  effects: Partial<ElementEffectProperties>,
): boolean {
  return Boolean(
    effects.focusScale ||
      effects.focusOpacity ||
      effects.focusOutline ||
      effects.focusBoxShadow,
  );
}

/**
 * Check if element has any active effects configured.
 */
export function hasActiveEffects(
  effects: Partial<ElementEffectProperties>,
): boolean {
  return Boolean(
    effects.activeScale ||
      effects.activeOpacity ||
      effects.activeBackgroundColor,
  );
}

/**
 * Check if element has any effects configured.
 */
export function hasAnyEffects(
  effects: Partial<ElementEffectProperties>,
): boolean {
  return (
    Boolean(effects.appearAnimation) ||
    hasHoverEffects(effects) ||
    hasFocusEffects(effects) ||
    hasActiveEffects(effects)
  );
}
