/**
 * Single Message Component
 * Displays a chat message (user or bot)
 * 
 * @since 1.5.0 - Added full appearance preset support
 */

import { useState, useCallback, useMemo } from 'react';
import { motion } from 'framer-motion';
import { Bot, User, Loader2 } from 'lucide-react';
import DOMPurify from 'dompurify';
import type { ChatMessage } from '@/types';
import { chatApi } from '@/api/chat';
import { useChatStore } from '@/store/chatStore';
import { getCartTelemetryFields, trackCommerceEvent } from '@/services/commerceTelemetry';
import { WidgetRenderer, type WidgetType } from './widgets';
import { resolveValue, resolveTypography, adjustColor, GlobalValues, clampTypography } from '@/utils/resolveAppearance';
import { sprintf, t } from '@/lib/i18n';
import { cartDebugLog, getWooCartCount } from '@/utils/cart';

interface SelectedWidget {
  type: WidgetType;
  id: number;
  config: Record<string, unknown>;
}

interface MessageProps {
  message: ChatMessage;
  isLast?: boolean;
}

export function Message({ message }: MessageProps) {
  const { config, visitorId, conversationId, currentBotId, messages: storeMessages, lastWidgetAssignments } = useChatStore();
  const isBot = message.role === 'bot';
  
  // Get global values and element settings
  const globalValues = (config.appearance_preset?.global_values || {}) as GlobalValues;
  const userSettings = config.element_settings?.userMessage || config.appearance_preset?.element_settings?.userMessage;
  const botSettings = config.element_settings?.botMessage || config.appearance_preset?.element_settings?.botMessage;
  
  // Fallback to primary color
  const primaryColor = config.primary_color || '#3BC2D0';
  
  // User message styling
  const userBg = resolveValue(userSettings?.background, globalValues, primaryColor);
  const userText = resolveValue(userSettings?.text, globalValues, '#FFFFFF');
  const userRadius = resolveValue(userSettings?.borderRadius, globalValues, '16px');
  const userPadding = resolveValue(userSettings?.padding, globalValues, '12px 16px');
  const userMaxWidth = resolveValue(userSettings?.maxWidth, globalValues, '80%');
  const userFontSize = resolveValue(userSettings?.fontSize, globalValues, '14px');
  const showUserAvatar = userSettings?.showAvatar !== false;
  const userAvatarSize = resolveValue(userSettings?.avatarSize, globalValues, '32px');
  const userAvatarBackground = resolveValue(userSettings?.avatarBackground, globalValues, '#E5E7EB');
  const userAvatarIconColor = resolveValue(userSettings?.avatarIconColor, globalValues, '#4B5563');
  const userAvatarIconSize = resolveValue(userSettings?.avatarIconSize, globalValues, '16px');
  
  // User typography with clamping
  const rawUserTypography = resolveTypography(
    userSettings?.typography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined,
    globalValues,
    { fontSize: userFontSize }
  );
  const userTypography = clampTypography(rawUserTypography, 'body');
  const userTimestampTypography = resolveTypography(
    userSettings?.timestampTypography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined,
    globalValues,
    {
      fontFamily: globalValues.typography?.fontFamily || 'inherit',
      fontSize: '10px',
      fontWeight: '400',
      lineHeight: '1',
      textTransform: 'none',
      fontStyle: 'normal',
      textDecoration: 'none',
      letterSpacing: '0px',
      textAlign: 'start',
    }
  );
  const userTimestampTextShadow = resolveValue(
    (userSettings?.timestampTypography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined)?.textShadow,
    globalValues,
    'none'
  );
  const userTimestampOpacity = resolveValue(userSettings?.timestampOpacity, globalValues, '0.6');
  
  // Bot message styling
  const botBg = resolveValue(botSettings?.background, globalValues, '#F9FAFB');
  const botText = resolveValue(botSettings?.text, globalValues, '#1F2937');
  const botRadius = resolveValue(botSettings?.borderRadius, globalValues, '8px');
  const botPadding = resolveValue(botSettings?.padding, globalValues, '8px 16px');
  const botMaxWidth = resolveValue(botSettings?.maxWidth, globalValues, '80%');
  const botFontSize = resolveValue(botSettings?.fontSize, globalValues, '14px');
  const showBotAvatar = botSettings?.showAvatar !== false;
  const botAvatarUrl = botSettings?.avatarUrl || config.avatar_url;
  const botAvatarSize = resolveValue(botSettings?.avatarSize, globalValues, '32px');
  const botAvatarBackground = resolveValue(botSettings?.avatarBackground, globalValues, '#3BC2D020');
  const botAvatarIconColor = resolveValue(botSettings?.avatarIconColor, globalValues, primaryColor);
  const botAvatarIconSize = resolveValue(botSettings?.avatarIconSize, globalValues, '16px');
  const botShadow = resolveValue(botSettings?.shadow, globalValues, '0 1px 2px rgba(0,0,0,0.05)');
  const botBorderColor = resolveValue(botSettings?.borderColor, globalValues, '#E5E7EB');
  const botBorderWidth = resolveValue(botSettings?.borderWidth, globalValues, '1px');
  
  // Bot typography with clamping
  const rawBotTypography = resolveTypography(
    botSettings?.typography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined,
    globalValues,
    { fontSize: botFontSize }
  );
  const botTypography = clampTypography(rawBotTypography, 'body');
  const botTimestampTypography = resolveTypography(
    botSettings?.timestampTypography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined,
    globalValues,
    {
      fontFamily: globalValues.typography?.fontFamily || 'inherit',
      fontSize: '10px',
      fontWeight: '400',
      lineHeight: '1',
      textTransform: 'none',
      fontStyle: 'normal',
      textDecoration: 'none',
      letterSpacing: '0px',
      textAlign: 'start',
    }
  );
  const botTimestampTextShadow = resolveValue(
    (botSettings?.timestampTypography as Record<string, import('@/utils/resolveAppearance').FieldValue | undefined> | undefined)?.textShadow,
    globalValues,
    'none'
  );
  const botTimestampOpacity = resolveValue(botSettings?.timestampOpacity, globalValues, '0.6');
  
  const hasWidgets = isBot && message.widgets && message.widgets.length > 0;
  
  // State for selected widget from picker
  const [selectedWidget, setSelectedWidget] = useState<SelectedWidget | null>(null);
  const [isLoadingWidget, setIsLoadingWidget] = useState(false);
  
  // Handle widget selection from picker
  const handleWidgetSelect = useCallback(async (option: { type: string; id: number; label: string }) => {
    if (lastWidgetAssignments && lastWidgetAssignments.length > 0) {
      const isAssigned = lastWidgetAssignments.some(
        assignment => assignment.id === option.id || assignment.type === option.type
      );
      if (!isAssigned) {
        console.warn('[BoostBot] Widget picker: rejected unassigned widget', option);
        return;
      }
    }

    setIsLoadingWidget(true);
    try {
      // Fetch widget config from public API (no auth needed)
      const response = await fetch(
        `${window.boostbot_config?.rest_url || '/wp-json/boostbot/v1'}/widgets/${option.id}/public?bot_id=${currentBotId || ''}`,
        {
          headers: {
            'X-WP-Nonce': window.boostbot_config?.nonce || '',
          },
        }
      );
      
      if (response.ok) {
        const data = await response.json();
        const widgetConfig = data.data?.widget || data.widget || data;
        
        // Parse config if it's a string
        let parsedConfig = widgetConfig.config;
        if (typeof parsedConfig === 'string') {
          try {
            parsedConfig = JSON.parse(parsedConfig);
          } catch {
            parsedConfig = {};
          }
        }
        
        // For form widgets, include fields in config
        if (option.type === 'form' && widgetConfig.fields) {
          parsedConfig = {
            ...parsedConfig,
            fields: widgetConfig.fields,
          };
        }
        
        setSelectedWidget({
          type: option.type as WidgetType,
          id: option.id,
          config: parsedConfig || {},
        });
      }
    } catch (error) {
      console.error('Failed to load widget:', error);
    } finally {
      setIsLoadingWidget(false);
    }
  }, [lastWidgetAssignments]);

  // Handle widget completion (calendar booking or form submission)
  const handleWidgetComplete = useCallback(async (result: unknown) => {
    const data = result as Record<string, unknown>;

    // Handle coupon copy — purely client-side, no server submission needed
    if (data.action === 'coupon_copy') {
      return;
    }

    // Handle product card actions (Add to Cart / View)
    if (data.product_id && data.action) {
      try {
        const action = data.action as string;
        const productId = Number(data.product_id);
        const quantity = Math.max(1, Number(data.quantity) || 1);
        const variationId = Math.max(0, Number(data.variation_id) || 0);
        const variation = typeof data.variation === 'object' && data.variation
          ? data.variation as Record<string, string>
          : {};

        // Build submission payload
        const payload = {
          widget_type: 'product_card',
          widget_id: selectedWidget?.id || (message.widgets?.[0]?.id ? Number(message.widgets[0].id) : 0),
          bot_id: Number(currentBotId) || 0,
          conversation_id: String(conversationId || ''),
          visitor_id: String(visitorId || ''),
          language: config.language || window.boostbot_config?.locale?.substring(0, 2) || 'he',
          source_page: window.location.href,
          data: {
            product_id: productId,
            action: action,
            quantity,
            variation_id: variationId,
            variation,
          },
        };

        const emitProductEvent = (event: Parameters<typeof trackCommerceEvent>[0], eventCart?: unknown) => {
          trackCommerceEvent({
            conversation_id: String(conversationId || ''),
            visitor_id: String(visitorId || ''),
            bot_id: Number(currentBotId) || null,
            language: config.language || window.boostbot_config?.locale?.substring(0, 2) || 'he',
            widget_type: 'product_card',
            widget_id: selectedWidget?.id || (message.widgets?.[0]?.id ? Number(message.widgets[0].id) : null),
            product_id: productId,
            quantity,
            variation_id: variationId || null,
            ...getCartTelemetryFields((eventCart ?? useChatStore.getState().cart) as any),
            ...event,
          });
        };

        if (action === 'view') {
          emitProductEvent({ event_type: 'product_viewed' });
        }

        const result = await chatApi.submitProductCard(payload);
        const responseCart = result.cart;

        if (action === 'add_to_cart') {
          cartDebugLog('product widget add_to_cart response', {
            count: getWooCartCount(responseCart),
            items: responseCart?.items.length ?? 0,
            cart_count: result.cartCount ?? null,
            is_empty: responseCart?.is_empty ?? true,
          });

          const currentStoreState = useChatStore.getState();
          const woo = currentStoreState.config?.woocommerce ?? window.boostbot_config?.woocommerce;
          if (woo?.active === true && woo?.show_cart_button === true) {
            if (responseCart) {
              currentStoreState.setCartState(responseCart);
            } else {
              await currentStoreState.refreshCart();
            }
          }

          emitProductEvent(
            { event_type: 'product_added_to_cart' },
            responseCart ?? useChatStore.getState().cart,
          );
        }

        const feedbackMessage = action === 'add_to_cart'
          ? t('Added to cart!')
          : result.message;

        if (!feedbackMessage) {
          return;
        }

        // Add a bot message with the success feedback
        useChatStore.getState().addMessage({
          id: `feedback-${Date.now()}`,
          role: 'bot',
          content: feedbackMessage,
          timestamp: new Date()
        });

        return {
          success: true,
          message: result.message || feedbackMessage || '',
        };
      } catch (error) {
        console.error('[BoostBot] Product action failed:', error);
        if (data.action === 'add_to_cart') {
          trackCommerceEvent({
            event_type: 'product_add_to_cart_failed',
            conversation_id: String(conversationId || ''),
            visitor_id: String(visitorId || ''),
            bot_id: Number(currentBotId) || null,
            language: config.language || window.boostbot_config?.locale?.substring(0, 2) || 'he',
            widget_type: 'product_card',
            widget_id: selectedWidget?.id || (message.widgets?.[0]?.id ? Number(message.widgets[0].id) : null),
            product_id: Number(data.product_id),
            quantity: Math.max(1, Number(data.quantity) || 1),
            variation_id: Math.max(0, Number(data.variation_id) || 0) || null,
            ...getCartTelemetryFields(useChatStore.getState().cart),
            metadata: {
              error: error instanceof Error ? error.message : null,
            },
          });
        }
        return {
          success: false,
          error: error instanceof Error ? error.message : t('Failed to add item to cart'),
        };
      }
    }
    
    // Check if this is a calendar booking (has date + time)
    if (data.date && data.time) {
      try {
        // Resolve widget info: prefer selectedWidget (from picker), then data.widget_id
        // (passed through WidgetRenderer callback), then fallback to message.widgets[0]
        const resolvedWidgetId = selectedWidget?.id
          ?? (data.widget_id != null ? Number(data.widget_id) : undefined)
          ?? (message.widgets?.length ? (
              typeof message.widgets[0].id === 'number'
                ? message.widgets[0].id
                : parseInt(String(message.widgets[0].id), 10) || undefined
            ) : undefined);

        // Snapshot conversation messages for the backend summary generator.
        // This bypasses the race condition where the async completeConversation()
        // hasn't persisted to the DB yet when book_meeting() tries to read it.
        const conversationMessages = storeMessages
          .filter(m => m.content && !m.isStreaming)
          .map(m => ({ role: m.role, content: m.content }));

        // Build booking request with complete page context
        const bookingData = {
          date: data.date as string,
          time: data.time as string,
          customer_name: data.name as string,
          customer_email: data.email as string,
          customer_phone: data.phone as string,
          widget_id: resolvedWidgetId,
          bot_id: Number(currentBotId) || 0,
          conversation_id: String(conversationId || ''),
          visitor_id: String(visitorId || ''),
          page_url: window.location.href,
          page_title: document.title,
          custom_fields: {} as Record<string, string>,
          conversation_messages: conversationMessages,
        };
        
        // Extract custom fields
        Object.keys(data).forEach(key => {
          if (key.startsWith('custom_')) {
            bookingData.custom_fields[key] = data[key] as string;
          }
        });
        
        // Send booking to API
        const response = await fetch(
          `${window.boostbot_config?.rest_url || '/wp-json/boostbot/v1'}/meetings/book`,
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-WP-Nonce': window.boostbot_config?.nonce || '',
            },
            body: JSON.stringify(bookingData),
          }
        );
        
        if (response.ok) {
          await response.json();
          // Keep the calendar widget visible so it can show its styled confirmation phase.
          return;
        } else {
          const errorData = await response.json();
          // Throw so the Calendar component can handle recovery (e.g. 409 conflict)
          throw new Error(errorData.message || t('Unable to book the appointment'));
        }
      } catch (error) {
        console.error('Failed to book meeting:', error);
        // Re-throw so the Calendar's handleSubmit can catch it and show inline error
        throw error;
      }
    }
    
    // Otherwise, treat as form submission - create a lead
    // This handles lead_form, contact_form, lead_capture, dynamic_form, form types
    // Use selectedWidget (from picker) OR the first widget from message.widgets (directly attached)
    const widgetInfo = selectedWidget || (message.widgets && message.widgets.length > 0 ? {
      type: message.widgets[0].type as WidgetType,
      id: typeof message.widgets[0].id === 'number' 
        ? message.widgets[0].id 
        : parseInt(String(message.widgets[0].id), 10) || 0,
      config: message.widgets[0].config || {},
    } : null);

    if (widgetInfo && Object.keys(data).length > 0) {
      try {
        // Determine widget type from widget info
        const widgetType = widgetInfo.type || 'lead_form';
        
        // Build form submission payload
        const formPayload = {
          widget_type: widgetType,
          widget_id: widgetInfo.id || 0,
          bot_id: Number(currentBotId) || 0,
          conversation_id: String(conversationId || ''),
          visitor_id: String(visitorId || ''),
          source_page: window.location.href,
          data: {} as Record<string, string>,
        };
        
        // Extract all form data as strings
        Object.keys(data).forEach(key => {
          const value = data[key];
          if (value !== undefined && value !== null) {
            formPayload.data[key] = String(value);
          }
        });
        
        // Submit to backend widget/{type}/submit endpoint
        const response = await fetch(
          `${window.boostbot_config?.rest_url || '/wp-json/boostbot/v1'}/widget/${widgetType}/submit`,
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-WP-Nonce': window.boostbot_config?.nonce || '',
            },
            body: JSON.stringify(formPayload),
          }
        );
        
        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}));
          console.error('[BoostBot] Form submission failed:', response.status, errorData);
          throw new Error(
            errorData?.message || sprintf(t('Form submission failed (HTTP %s)'), response.status)
          );
        } else {
          console.log('[BoostBot] Form submitted successfully');
        }
      } catch (error) {
        console.error('[BoostBot] Failed to submit form:', error);
        throw error; // Re-throw so LeadForm can catch and display error
      }
    }
  }, [selectedWidget, message.widgets, config, visitorId, conversationId, currentBotId]);
  
  // Get message styles based on role
  const messageStyles = useMemo(() => {
    if (isBot) {
      return {
        backgroundColor: botBg,
        color: botText,
        borderRadius: botRadius,
        borderTopLeftRadius: '0',
        padding: botPadding,
        maxWidth: botMaxWidth,
        boxShadow: botShadow,
        border: `${botBorderWidth} solid ${botBorderColor}`,
        // Typography
        ...botTypography,
      };
    } else {
      return {
        background: `linear-gradient(135deg, ${userBg} 0%, ${adjustColor(userBg, -20)} 100%)`,
        color: userText,
        borderRadius: userRadius,
        borderTopRightRadius: '0',
        padding: userPadding,
        maxWidth: userMaxWidth,
        // Typography
        ...userTypography,
      };
    }
  }, [isBot, userBg, userText, userRadius, userPadding, userMaxWidth, userTypography, botBg, botText, botRadius, botPadding, botMaxWidth, botTypography, botShadow, botBorderColor, botBorderWidth]);

  const timestampTypography = isBot ? botTimestampTypography : userTimestampTypography;
  const timestampOpacity = isBot ? botTimestampOpacity : userTimestampOpacity;
  const timestampTextShadow = isBot ? botTimestampTextShadow : userTimestampTextShadow;
  const parsedUserAvatarIconSize = Number.parseFloat(String(userAvatarIconSize)) || 16;
  const parsedBotAvatarIconSize = Number.parseFloat(String(botAvatarIconSize)) || 16;
  
  return (
    <motion.div
      className={`bb-message flex flex-col ${isBot ? 'bb-message-bot' : 'bb-message-user'}`}
      initial={{ opacity: 0, y: 10, scale: 0.95 }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      transition={{ 
        type: 'spring',
        stiffness: 500,
        damping: 30
      }}
      layout
    >
      {/* Message Row */}
      <div className={`bb-message-row flex gap-2 ${isBot ? 'justify-start' : 'justify-end'}`}>
        {/* Bot avatar */}
        {isBot && showBotAvatar && (
          <div 
            className="bb-bot-avatar rounded-full flex items-center justify-center flex-shrink-0"
            style={{ backgroundColor: botAvatarBackground, width: botAvatarSize, height: botAvatarSize }}
          >
            {botAvatarUrl ? (
              <img 
                src={botAvatarUrl} 
                alt="" 
                className="bb-bot-avatar-image rounded-full object-cover"
                style={{ width: botAvatarSize, height: botAvatarSize }}
              />
            ) : (
              <Bot className="bb-bot-avatar-icon" size={parsedBotAvatarIconSize} style={{ color: botAvatarIconColor }} />
            )}
          </div>
        )}
        
        {/* Message bubble */}
        <div className={`bb-message-bubble ${isBot ? 'bb-bot-message' : 'bb-user-message'}`} style={messageStyles}>
          {/* Text content */}
          <MessageContent 
            content={message.content} 
            isStreaming={message.isStreaming}
            textColor={isBot ? botText : userText}
          />
          
          {/* Timestamp */}
          <span 
            className="text-[10px] mt-1 block"
          style={{
            opacity: Number.parseFloat(String(timestampOpacity)) || 0.6,
            textShadow: timestampTextShadow !== 'none' ? timestampTextShadow : undefined,
            ...timestampTypography,
          }}
          >
            {formatTime(message.timestamp)}
          </span>
        </div>
        
        {/* User avatar */}
      {!isBot && showUserAvatar && (
        <div
          className="bb-user-avatar flex items-center justify-center flex-shrink-0 rounded-full"
          style={{
            width: userAvatarSize,
            height: userAvatarSize,
            backgroundColor: userAvatarBackground,
          }}
        >
          <User
            className="bb-user-avatar-icon"
            size={parsedUserAvatarIconSize}
            style={{ color: userAvatarIconColor }}
          />
        </div>
        )}
      </div>
      
      {/* Widgets Row - Below the message */}
      {hasWidgets && (
        <div className="bb-message-widgets mt-3 space-y-3" style={{ marginInlineEnd: '2.5rem' }}>
          {/* Show selected widget if one was picked */}
          {selectedWidget && (
            <motion.div
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              transition={{ type: 'spring', stiffness: 400, damping: 25 }}
            >
              <WidgetRenderer
                widget={{
                  type: selectedWidget.type,
                  config: selectedWidget.config,
                  id: String(selectedWidget.id),
                }}
                onComplete={handleWidgetComplete}
                isRTL={window.boostbot_config?.is_rtl ?? true}
              />
            </motion.div>
          )}
          
          {/* Loading indicator when fetching widget */}
          {isLoadingWidget && (
            <motion.div
              className="flex items-center justify-center py-4"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
            >
              <Loader2 className="w-6 h-6 animate-spin text-gray-400" />
            </motion.div>
          )}
          
          {/* Regular widgets (including widget_picker if no selection yet) */}
          {!selectedWidget && !isLoadingWidget && message.widgets!.map((widget, index) => (
            <WidgetRenderer
              key={`widget-${index}`}
              widget={{
                type: widget.type as WidgetType,
                config: widget.config || widget.data || {},
                id: widget.id,
              }}
              onComplete={handleWidgetComplete}
              onWidgetSelect={handleWidgetSelect}
              isRTL={window.boostbot_config?.is_rtl ?? true}
            />
          ))}
        </div>
      )}
    </motion.div>
  );
}

/**
 * Message content with rich formatting support
 * Professional pricing cards, feature lists, and beautiful formatting
 * Supports HTML with sanitization for security
 */
function MessageContent({ content: rawContent, isStreaming, textColor }: { content: string; isStreaming?: boolean; textColor?: string }) {
  const content = typeof rawContent === 'string' ? rawContent : String(rawContent ?? '');

  // Strip AI-hallucinated tool/code artifacts that leak into the visible response.
  // GPT sometimes invents tool_code blocks, function calls, or widget tokens
  // when it tries to "trigger" a widget on its own. These are never valid and
  // should be silently removed so the user sees clean text.
  const cleanedContent = useMemo(() => {
    let text = content;
    // Remove ```tool_code ... ``` blocks (Gemini-style tool invocation leaked into GPT output)
    text = text.replace(/```\s*tool_code[\s\S]*?```/gi, '');
    // Remove [WIDGET:...] or [TOOL:...] style tokens
    text = text.replace(/\[(WIDGET|TOOL|FUNCTION)[^\]]*\]/gi, '');
    // Remove [LEAD_SAVE:...] tokens (server-side only, should never reach UI)
    text = text.replace(/\[LEAD_SAVE:[^\]]*\]/gi, '');
    // Remove standalone tool_code lines (without backticks)
    text = text.replace(/^\s*tool_code\s+\w+.*$/gm, '');
    // Remove leaked WIDGET_ATTACHED system instructions (should never reach user)
    text = text.replace(/⚠️\s*WIDGET_ATTACHED:[\s\S]*?(?=\n\n|$)/gi, '');
    // Remove empty code blocks that might remain
    text = text.replace(/```\s*```/g, '');
    // Remove stray triple-backtick fences with no content
    text = text.replace(/```\w*\s*```/g, '');
    // Collapse excessive whitespace left behind
    text = text.replace(/\n{3,}/g, '\n\n').trim();
    return text;
  }, [content]);

  // Check if content contains HTML tags
  const containsHtml = useMemo(() => {
    // Look for HTML-like patterns: <tag>, </tag>, or <tag />
    return /<[a-z][\s\S]*>/i.test(cleanedContent);
  }, [cleanedContent]);
  
  // Sanitize HTML content for security
  const sanitizedHtml = useMemo(() => {
    if (!containsHtml) return null;
    
    // Configure DOMPurify to allow safe styling
    const cleanHtml = DOMPurify.sanitize(cleanedContent, {
      ALLOWED_TAGS: ['div', 'span', 'p', 'br', 'strong', 'b', 'em', 'i', 'u', 'a', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'table', 'tr', 'td', 'th', 'thead', 'tbody'],
      ALLOWED_ATTR: ['style', 'class', 'href', 'target', 'rel'],
      // Allow inline styles but sanitize them
      ALLOW_DATA_ATTR: false,
    });
    
    return cleanHtml;
  }, [cleanedContent, containsHtml]);
  
  // If content contains HTML, render it safely
  if (containsHtml && sanitizedHtml) {
    return (
      <div>
        <div 
          className="html-content"
          dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
          style={{ 
            fontSize: '14px', 
            lineHeight: 1.6,
            color: textColor,
          }}
        />
        {isStreaming && (
          <motion.span
            className="inline-block w-1.5 h-4 bg-current ms-1 rounded"
            animate={{ opacity: [1, 0] }}
            transition={{ duration: 0.5, repeat: Infinity }}
          />
        )}
      </div>
    );
  }
  
  // Parse and render rich content - simplified, reliable detection
  const renderRichContent = (text: string) => {
    // NOTE: Package card rendering (renderPackageCards) removed - too fragile
    // The regex-based parsing broke frequently when text format varied.
    // Now using structured content which handles all cases reliably.
    
    console.log('[BoostBot][Message] renderRichContent called, text length:', text.length);
    
    const hasBullets = text.includes('•');
    const hasListMarkers = /\n\s*[-•✓]\s/.test(text);
    
    console.log('[BoostBot][Message] Content detection:', { hasBullets, hasListMarkers });
    
    // Check for bullet lists (with or without newlines)
    if (hasBullets || hasListMarkers) {
      console.log('[BoostBot][Message] Using renderStructuredContent');
      return renderStructuredContent(text);
    }
    
    // Regular content with nice formatting
    console.log('[BoostBot][Message] Using renderBasicContent');
    return renderBasicContent(text);
  };
  
  // _renderDetailCard, parsePackages, _renderPackageCards removed — regex-based card parsing was too fragile.
  // Originals archived to _archive/message-card-renderers/ for reference.

  // Render content with bullet lists - handles both newlines and inline bullets
  const renderStructuredContent = (text: string) => {
    // First, normalize the text - split inline bullets into lines
    let normalizedText = text;
    // Convert inline bullets to newlines
    normalizedText = normalizedText.replace(/\s*•\s*/g, '\n• ');
    
    const lines = normalizedText.split('\n');
    const elements: JSX.Element[] = [];
    let currentList: string[] = [];
    let currentHeader = '';
    let keyIndex = 0;
    
    const flushList = () => {
      if (currentList.length > 0) {
        elements.push(
          <div 
            key={`section-${keyIndex++}`} 
            style={{
              backgroundColor: '#f8fafc',
              borderRadius: '10px',
              padding: '12px 14px',
              marginTop: '8px',
              marginBottom: '8px',
              border: '1px solid #e2e8f0'
            }}
          >
            {currentHeader && (
              <h4 
                style={{ 
                  fontWeight: 600, 
                  fontSize: '14px',
                  color: '#1f2937',
                  marginBottom: '10px',
                  display: 'flex',
                  alignItems: 'center',
                  gap: '6px'
                }}
              >
                <span style={{ 
                  width: '3px', 
                  height: '14px', 
                  backgroundColor: '#06B6D4',
                  borderRadius: '2px'
                }}></span>
                {currentHeader}
              </h4>
            )}
            <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
              {currentList.map((item, idx) => (
                <li 
                  key={idx} 
                  style={{
                    display: 'flex',
                    alignItems: 'flex-start',
                    gap: '8px',
                    fontSize: '13px',
                    color: '#374151',
                    marginBottom: '6px',
                    lineHeight: 1.5
                  }}
                >
                  <span style={{ color: '#10B981', flexShrink: 0, marginTop: '2px' }}>✓</span>
                  <span>{renderInlineFormatting(item)}</span>
                </li>
              ))}
            </ul>
          </div>
        );
        currentList = [];
        currentHeader = '';
      }
    };
    
    lines.forEach((line) => {
      const trimmed = line.trim();
      
      // Check for bullet point
      if (trimmed.startsWith('•') || trimmed.startsWith('- ') || trimmed.startsWith('* ') || trimmed.startsWith('✓')) {
        const content = trimmed.replace(/^[•\-\*✓]\s*/, '').trim();
        if (content && content.length > 1) {
          currentList.push(content);
        }
      }
      // Check for header (## or **Title** or "כותרת:")
      else if (trimmed.startsWith('##') || 
               (trimmed.startsWith('**') && trimmed.endsWith('**')) ||
               trimmed.match(/^[^:]{2,30}:$/)) {
        flushList();
        currentHeader = trimmed
          .replace(/^#+\s*/, '')
          .replace(/^\*\*|\*\*$/g, '')
          .replace(/:$/, '');
      }
      // Regular text
      else if (trimmed) {
        flushList();
        // Check if this looks like a question (at the end)
        const isQuestion = trimmed.includes('?') || trimmed.match(/^(איזו|איזה|מה|אשמח|נשמח|what|how|can|would|do|which|where|when|why|who)/i);
        elements.push(
          <p 
            key={`p-${keyIndex++}`} 
            style={{ 
              fontSize: '14px',
              lineHeight: 1.6,
              color: textColor,
              marginBottom: isQuestion ? '0' : '8px'
            }}
          >
            {renderInlineFormatting(trimmed)}
          </p>
        );
      }
    });
    
    flushList();
    return <div>{elements}</div>;
  };
  
  // Render basic content with nice formatting
  const renderBasicContent = (text: string) => {
    // Split into paragraphs
    const paragraphs = text.split(/\n\n+/);
    
    if (paragraphs.length === 1) {
      return (
        <p style={{ 
          fontSize: '14px', 
          lineHeight: 1.6, 
          color: textColor
        }}>
          {renderInlineFormatting(text)}
        </p>
      );
    }
    
    return (
      <div>
        {paragraphs.map((para, idx) => (
          <p 
            key={idx}
            style={{ 
              fontSize: '14px', 
              lineHeight: 1.6, 
              color: textColor,
              marginBottom: idx < paragraphs.length - 1 ? '10px' : '0'
            }}
          >
            {renderInlineFormatting(para.trim())}
          </p>
        ))}
      </div>
    );
  };
  
  // Handle inline formatting (bold, links, prices, specs)
  const renderInlineFormatting = (text: string): React.ReactNode => {
    const parts: (string | JSX.Element)[] = [];
    
    // Combined regex for: **bold**, prices, markdown links, plain links
    const formatRegex = /(\*\*[^*]+\*\*)|((?:₪|\$|€|£)\s?[\d,]+(?:\.\d{1,2})?)|(\[([^\]]+)\]\(([^)]+)\))|((https?:\/\/)[^\s]+)/g;
    
    let lastIndex = 0;
    let match;
    let keyIndex = 0;
    
    while ((match = formatRegex.exec(text)) !== null) {
      // Add text before the match
      if (match.index > lastIndex) {
        parts.push(text.slice(lastIndex, match.index));
      }
      
      if (match[1]) {
        // Bold text **text**
        const boldText = match[1].replace(/^\*\*|\*\*$/g, '');
        parts.push(
          <strong key={`bold-${keyIndex++}`} className="font-semibold" style={{ color: 'inherit' }}>
            {boldText}
          </strong>
        );
      } else if (match[2]) {
        // Price ₪xxx - highlight prominently
        parts.push(
          <span 
            key={`price-${keyIndex++}`} 
            className="font-bold text-emerald-600"
          >
            {match[2]}
          </span>
        );
      } else if (match[3]) {
        // Markdown link [text](url) — only allow safe schemes; otherwise render the label
        // as plain text so a javascript:/data: URL in bot/user content cannot be clicked.
        const mdSafeHref = /^(https?:|mailto:|tel:)/i.test((match[5] || '').trim()) ? match[5] : undefined;
        parts.push(
          mdSafeHref ? (
            <a
              key={`link-${keyIndex++}`}
              href={mdSafeHref}
              target="_blank"
              rel="noopener noreferrer"
              className="text-primary-500 hover:underline font-medium"
            >
              {match[4]}
            </a>
          ) : (
            <span key={`link-${keyIndex++}`} className="font-medium">{match[4]}</span>
          )
        );
      } else if (match[6]) {
        // Plain URL
        parts.push(
          <a
            key={`link-${keyIndex++}`}
            href={match[6]}
            target="_blank"
            rel="noopener noreferrer"
            className="text-primary-500 hover:underline font-medium"
          >
            {match[6]}
          </a>
        );
      }
      
      lastIndex = match.index + match[0].length;
    }
    
    // Add remaining text
    if (lastIndex < text.length) {
      parts.push(text.slice(lastIndex));
    }
    
    return parts.length > 0 ? parts : text;
  };

  return (
    <div>
      {renderRichContent(cleanedContent)}
      {isStreaming && (
        <motion.span
          className="inline-block w-1.5 h-4 bg-current ms-1 rounded"
          animate={{ opacity: [1, 0] }}
          transition={{ duration: 0.5, repeat: Infinity }}
        />
      )}
    </div>
  );
}

/**
 * Format timestamp
 */
function formatTime(date: Date): string {
  return new Date(date).toLocaleTimeString(undefined, { 
    hour: '2-digit', 
    minute: '2-digit' 
  });
}
