/**
 * Chat Bubble Component
 * The floating button that opens/closes the chat widget
 * 
 * @since 1.5.0 - Added full appearance preset support
 */

import { motion, AnimatePresence } from 'framer-motion';
import {
  MessageCircle,
  X,
  Bot,
  Sparkles,
  MessageSquare,
  Headphones,
  User,
  Users,
  UserCheck,
  Mail,
  Send,
  Phone,
  PhoneCall,
  PhoneIncoming,
  Video,
  Camera,
  Monitor,
  MapPin,
  Home,
  Building,
  Calendar,
  Clock,
  Coffee,
  Star,
  Heart,
  Zap,
  Briefcase,
  ShoppingBag,
  Gift,
  Shield,
  Lock,
  Unlock,
  Bell,
  Search,
  Settings,
  Check,
  ChevronDown,
  type LucideIcon,
} from 'lucide-react';
import { useChatStore } from '@/store/chatStore';
import { resolveValue, createGradient, GlobalValues, clampHeight } from '@/utils/resolveAppearance';
import { t } from '@/lib/i18n';

// Icon map for different icon types
const ICON_MAP: Record<string, LucideIcon> = {
  // Wide Lucide set (must match the admin picker options)
  'bot': Bot,
  'message-circle': MessageCircle,
  'sparkles': Sparkles,
  'headphones': Headphones,
  'user': User,
  'users': Users,
  'user-check': UserCheck,
  'mail': Mail,
  'send': Send,
  'phone': Phone,
  'phone-call': PhoneCall,
  'phone-incoming': PhoneIncoming,
  'video': Video,
  'camera': Camera,
  'monitor': Monitor,
  'map-pin': MapPin,
  'home': Home,
  'building': Building,
  'calendar': Calendar,
  'clock': Clock,
  'coffee': Coffee,
  'star': Star,
  'heart': Heart,
  'zap': Zap,
  'briefcase': Briefcase,
  'shopping-bag': ShoppingBag,
  'gift': Gift,
  'shield': Shield,
  'lock': Lock,
  'unlock': Unlock,
  'bell': Bell,
  'search': Search,
  'settings': Settings,
  'check': Check,
  'x': X,
  'chevron-down': ChevronDown,

  // Legacy aliases (backward compatibility)
  'robot': Bot,
  'chat': MessageCircle,
  'message': MessageSquare,
};

export function ChatBubble() {
  const { isOpen, toggleChat, unreadCount, config } = useChatStore();
  
  const resolveNumber = (value: string | undefined, fallback: number) => {
    const n = Number.parseFloat(String(value ?? ''));
    return Number.isFinite(n) ? n : fallback;
  };

  const resolveDurationSeconds = (value: string | undefined, fallback: number) => {
    const raw = String(value ?? '').trim();
    if (!raw) return fallback;
    if (raw.endsWith('ms')) {
      const n = Number.parseFloat(raw.replace('ms', ''));
      return Number.isFinite(n) ? n / 1000 : fallback;
    }
    if (raw.endsWith('s')) {
      const n = Number.parseFloat(raw.replace('s', ''));
      return Number.isFinite(n) ? n : fallback;
    }
    const n = Number.parseFloat(raw);
    return Number.isFinite(n) ? n : fallback;
  };

  // Get appearance settings
  const globalValues = (config.appearance_preset?.global_values || {}) as GlobalValues;
  const bubbleSettings = config.element_settings?.chatBubble || config.appearance_preset?.element_settings?.chatBubble;
  const appearance = (config as any).appearance as { primary_color?: string; position?: string } | undefined;
  
  // Resolve bubble settings with defaults and clamping
  const rawSize = resolveValue(bubbleSettings?.size, globalValues, '60px');
  const size = clampHeight(rawSize, 'chatBubble', '60px');
  // Get background - use chatBubble.background if set, otherwise fall back to primary color
  const rawBackground = resolveValue(bubbleSettings?.background, globalValues, '');
  const background =
    rawBackground ||
    appearance?.primary_color ||
    config.primary_color ||
    '#3BC2D0';
  const margin = (() => {
    const m = (bubbleSettings as any)?.margin
    if (m && typeof m === 'object' && 'top' in m && 'right' in m && 'bottom' in m && 'left' in m) {
      return {
        top: m.top || '24px',
        right: m.right || '24px',
        bottom: m.bottom || '24px',
        left: m.left || '24px',
      }
    }
    const resolved = resolveValue(m, globalValues, '24px')
    return { top: resolved, right: resolved, bottom: resolved, left: resolved }
  })();
  const animation = bubbleSettings?.animation ?? 'none';
  const iconTypeRaw = bubbleSettings?.icon || 'bot';
  const position = (bubbleSettings?.position || (appearance?.position as any) || config.position || 'bottom-right') as
    | 'bottom-right'
    | 'bottom-left'
    | 'top-right'
    | 'top-left';
  const customIconUrl = bubbleSettings?.customIconUrl;
  
  // Get the icon component
  const iconLegacyMap: Record<string, string> = {
    robot: 'bot',
    chat: 'message-circle',
    message: 'message-circle',
    sparkles: 'sparkles',
    headphones: 'headphones',
  };
  const iconType = iconLegacyMap[String(iconTypeRaw)] || String(iconTypeRaw);
  const IconComponent = ICON_MAP[iconType] || MessageCircle;
  
  // Calculate icon size (40% of bubble size)
  const sizeNum = parseInt(size) || 60;
  const iconSizeDefault = `${Math.round(sizeNum * 0.4)}px`;
  const iconSizeRaw = resolveValue((bubbleSettings as any)?.iconSize, globalValues, iconSizeDefault);
  const iconSize = Number.parseInt(String(iconSizeRaw), 10) || Math.round(sizeNum * 0.4);

  const iconColor = resolveValue((bubbleSettings as any)?.iconColor, globalValues, '#FFFFFF');
  const shadow = resolveValue((bubbleSettings as any)?.shadow, globalValues, '0 4px 20px rgba(0,0,0,0.2)');
  const borderType = (bubbleSettings as any)?.borderType || 'none';
  const borderWidth = (() => {
    const bw = (bubbleSettings as any)?.borderWidth;
    if (bw && typeof bw === 'object' && 'top' in bw && 'right' in bw && 'bottom' in bw && 'left' in bw) {
      const o = bw as { top?: string; right?: string; bottom?: string; left?: string };
      return `${o.top || '0px'} ${o.right || '0px'} ${o.bottom || '0px'} ${o.left || '0px'}`;
    }
    return resolveValue(bw, globalValues, '0px');
  })();
  const borderColor = resolveValue((bubbleSettings as any)?.borderColor, globalValues, 'transparent');
  const borderRadius = resolveValue((bubbleSettings as any)?.borderRadius, globalValues, '9999px');

  const unreadBadge = (bubbleSettings as any)?.unreadBadge || {};
  const badgeBackground = resolveValue(unreadBadge.background, globalValues, '#EF4444');
  const badgeTextColor = resolveValue(unreadBadge.textColor, globalValues, '#FFFFFF');
  const badgeSize = resolveValue(unreadBadge.size, globalValues, '20px');
  const badgeMinWidth = resolveValue(unreadBadge.minWidth, globalValues, '20px');
  const badgePaddingX = resolveValue(unreadBadge.paddingX, globalValues, '4px');
  const badgeOffsetX = resolveValue(unreadBadge.offsetX, globalValues, '-4px');
  const badgeOffsetY = resolveValue(unreadBadge.offsetY, globalValues, '-4px');
  const badgeBorderRadius = resolveValue(unreadBadge.borderRadius, globalValues, '9999px');
  const badgeTypography = unreadBadge.typography || {};
  const badgeFontFamily = resolveValue(badgeTypography.fontFamily, globalValues, globalValues.typography?.fontFamily || 'inherit');
  const badgeFontSize = resolveValue(badgeTypography.fontSize, globalValues, globalValues.typography?.label?.fontSize || '12px');
  const badgeFontWeight = resolveValue(badgeTypography.fontWeight, globalValues, globalValues.typography?.label?.fontWeight || '700');
  const badgeLineHeight = resolveValue(badgeTypography.lineHeight, globalValues, globalValues.typography?.label?.lineHeight || '1.1');
  const badgeTextTransform = resolveValue(badgeTypography.textTransform, globalValues, 'none');
  const badgeFontStyle = resolveValue(badgeTypography.fontStyle, globalValues, 'normal');
  const badgeTextDecoration = resolveValue(badgeTypography.textDecoration, globalValues, 'none');
  const badgeLetterSpacing = resolveValue(badgeTypography.letterSpacing, globalValues, '0');
  const badgeTextShadow = resolveValue(badgeTypography.textShadow, globalValues, 'none');
  const badgeTextAlign = resolveValue(badgeTypography.textAlign, globalValues, 'start');

  const pulseRing = (bubbleSettings as any)?.pulseRing || {};
  const ringColor = resolveValue(pulseRing.color, globalValues, background || '#3BC2D0');
  const ringScale = resolveNumber(resolveValue(pulseRing.scale, globalValues, '1.2'), 1.2);
  const ringOpacityStart = resolveNumber(resolveValue(pulseRing.opacityStart, globalValues, '0.5'), 0.5);
  const ringOpacityEnd = resolveNumber(resolveValue(pulseRing.opacityEnd, globalValues, '0'), 0);
  const ringDuration = resolveDurationSeconds(resolveValue(pulseRing.duration, globalValues, '1.5s'), 1.5);

  // Resolve the primary color for the glow animation
  const primaryColor = background || '#3BC2D0';
  
  // Position styles
  const positionStyles =
    position === 'bottom-left'
      ? { left: margin.left, right: 'auto', bottom: margin.bottom, top: 'auto' }
      : position === 'top-left'
        ? { left: margin.left, right: 'auto', top: margin.top, bottom: 'auto' }
        : position === 'top-right'
          ? { right: margin.right, left: 'auto', top: margin.top, bottom: 'auto' }
          : { right: margin.right, left: 'auto', bottom: margin.bottom, top: 'auto' };
  
  // Helper: convert a hex/CSS color to rgba for the glow animation
  const hexToRgba = (color: string, alpha: number): string => {
    // Handle hex colors
    const hex = color.replace('#', '');
    if (/^[0-9a-fA-F]{6}$/.test(hex)) {
      const r = parseInt(hex.substring(0, 2), 16);
      const g = parseInt(hex.substring(2, 4), 16);
      const b = parseInt(hex.substring(4, 6), 16);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }
    if (/^[0-9a-fA-F]{3}$/.test(hex)) {
      const r = parseInt(hex[0] + hex[0], 16);
      const g = parseInt(hex[1] + hex[1], 16);
      const b = parseInt(hex[2] + hex[2], 16);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }
    // Fallback for non-hex colors (gradients, etc.) — use the default teal
    return `rgba(59, 194, 208, ${alpha})`;
  };

  // Get animation based on setting — all values are hardcoded (granular settings removed)
  const getAnimation = () => {
    if (isOpen) return {}; // No animation when open
    
    switch (animation) {
      case 'none': return {};
      case 'pulse': return {
        scale: [1, 1.05, 1],
        transition: { duration: 2, repeat: Infinity, ease: 'easeInOut' }
      };
      case 'bounce': return {
        y: [0, '-8px', 0],
        transition: { duration: 0.6, repeat: Infinity, ease: 'easeInOut' }
      };
      case 'shake': return {
        rotate: [-3, 3, -3, 3, 0],
        transition: { duration: 0.5, repeat: Infinity, repeatDelay: 3 }
      };
      case 'glow': return {
        boxShadow: [
          `0 0 0px ${hexToRgba(primaryColor, 0)}`,
          `0 0 20px ${hexToRgba(primaryColor, 0.6)}`,
          `0 0 0px ${hexToRgba(primaryColor, 0)}`,
        ],
        transition: { duration: 2, repeat: Infinity, ease: 'easeInOut' }
      };
      case 'wiggle': return {
        x: [0, -3, 3, -3, 3, 0],
        transition: { duration: 0.5, repeat: Infinity, repeatDelay: 3, ease: 'easeInOut' }
      };
      case 'float': return {
        y: [0, -6, 0],
        transition: { duration: 3, repeat: Infinity, ease: 'easeInOut' }
      };
      default: return {};
    }
  };
  
  return (
    <motion.button
      className="bb-chat-bubble fixed z-[999999] flex items-center justify-center text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2"
      style={{
        ...positionStyles,
        width: size,
        height: size,
        borderRadius,
        // IMPORTANT: our widget CSS includes a reset that sets `button { background-image: none !important; }`
        // which will override inline gradients. We therefore set the bubble background via CSS variables
        // and apply the actual background-image with `!important` in widget.css for `.bb-chat-bubble`.
        backgroundColor: background,
        ['--bb-chat-bubble-bg-image' as any]: createGradient(background),
        ['--bb-chat-bubble-bg-color' as any]: background,
        boxShadow: shadow,
        borderStyle: borderType === 'none' ? 'none' : borderType,
        borderWidth: borderType === 'none' ? '0' : borderWidth,
        borderColor: borderType === 'none' ? 'transparent' : borderColor,
      }}
      onClick={toggleChat}
      initial={{ scale: 0, opacity: 0 }}
      animate={{ 
        scale: 1, 
        opacity: 1,
        ...getAnimation()
      }}
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.95 }}
      aria-label={isOpen ? t('Close chat') : t('Open chat')}
      aria-expanded={isOpen}
    >
      <AnimatePresence mode="wait">
        {isOpen ? (
          <motion.div
            key="close"
            initial={{ rotate: -90, opacity: 0 }}
            animate={{ rotate: 0, opacity: 1 }}
            exit={{ rotate: 90, opacity: 0 }}
            transition={{ duration: 0.2 }}
          >
            <X className="bb-chat-bubble-icon" style={{ width: iconSize, height: iconSize, color: iconColor }} />
          </motion.div>
        ) : (
          <motion.div
            key="open"
            initial={{ rotate: 90, opacity: 0 }}
            animate={{ rotate: 0, opacity: 1 }}
            exit={{ rotate: -90, opacity: 0 }}
            transition={{ duration: 0.2 }}
          >
            {customIconUrl ? (
              <img 
                src={customIconUrl} 
                alt="" 
                className="bb-chat-bubble-custom-icon"
                style={{ 
                  width: iconSize * 1.2, 
                  height: iconSize * 1.2,
                  borderRadius: '50%',
                  objectFit: 'cover',
                }}
              />
            ) : (
              <IconComponent className="bb-chat-bubble-icon" style={{ width: iconSize, height: iconSize, color: iconColor }} />
            )}
          </motion.div>
        )}
      </AnimatePresence>
      
      {/* Unread badge */}
      <AnimatePresence>
        {!isOpen && unreadCount > 0 && (
          <motion.span
            className="absolute flex items-center justify-center"
            style={{
              top: badgeOffsetY,
              [position === 'bottom-left' || position === 'top-left' ? 'right' : 'left']: badgeOffsetX,
              minWidth: badgeMinWidth,
              height: badgeSize,
              paddingInlineStart: badgePaddingX,
              paddingInlineEnd: badgePaddingX,
              borderRadius: badgeBorderRadius,
              background: badgeBackground,
              color: badgeTextColor,
              fontFamily: badgeFontFamily,
              fontSize: badgeFontSize,
              fontWeight: badgeFontWeight,
              lineHeight: badgeLineHeight,
              textTransform: badgeTextTransform,
              fontStyle: badgeFontStyle,
              textDecoration: badgeTextDecoration,
              letterSpacing: badgeLetterSpacing,
              textShadow: badgeTextShadow !== 'none' ? badgeTextShadow : undefined,
              textAlign: (badgeTextAlign || 'center') as React.CSSProperties['textAlign'],
            }}
            initial={{ scale: 0 }}
            animate={{ scale: 1 }}
            exit={{ scale: 0 }}
          >
            {unreadCount > 9 ? '9+' : unreadCount}
          </motion.span>
        )}
      </AnimatePresence>
      
      {/* Pulse ring animation for unread — suppressed when animation is 'none' */}
      {animation !== 'none' && !isOpen && unreadCount > 0 && (
        <motion.span 
          className="absolute inset-0 rounded-full"
          style={{ backgroundColor: ringColor || background }}
          animate={{
            scale: [1, ringScale, ringScale],
            opacity: [ringOpacityStart, ringOpacityEnd, 0],
          }}
          transition={{
            duration: ringDuration,
            repeat: Infinity,
            ease: 'easeOut',
          }}
        />
      )}
    </motion.button>
  );
}
