import React, { useState, useEffect, useMemo, memo } from 'react';
import { MdStars, MdAutorenew, MdCardGiftcard, MdRefresh, MdReply, MdContentCopy, MdRedeem } from 'react-icons/md';
import { GiHeartBeats } from 'react-icons/gi';
import { FaUsers } from 'react-icons/fa';
import type { ChatMessage, Platform } from '../lib/types';
import { parseMessageWithEmotes } from '../lib/emotes';

interface ChatDisplayProps {
  messages: ChatMessage[];
  isLoading: boolean;
  selectedPlatforms: Platform[];
  onReply?: (message: ChatMessage) => void;
  channelName?: string;
  channelDisplayName?: string;
  streamTitle?: string;
  isStreamLive?: boolean;
  streamUptime?: string;
  viewerCount?: number | null;
  onRefreshEmotes?: () => void;
  isRefreshingEmotes?: boolean;
  onToggleSidebar?: () => void;
  sidebarVisible?: boolean;
  onCopyMessage?: () => void;
  showStreamEmbed?: boolean;
  onToggleStreamEmbed?: () => void;
  currentUserDisplayName?: string;
  fontSize?: number;
  /** When provided (unified chat mode), renders this instead of the normal messages area */
  unifiedChatSlot?: React.ReactNode;
}

function ChatDisplay({
  messages,
  isLoading,
  selectedPlatforms,
  onReply,
  channelName,
  channelDisplayName,
  streamTitle,
  isStreamLive,
  streamUptime,
  viewerCount,
  onRefreshEmotes,
  isRefreshingEmotes = false,
  onToggleSidebar,
  sidebarVisible = true,
  onCopyMessage,
  showStreamEmbed = true,
  onToggleStreamEmbed,
  currentUserDisplayName,
  fontSize = 14,
  unifiedChatSlot,
}: ChatDisplayProps) {
  const [filteredMessages, setFilteredMessages] = useState<ChatMessage[]>([]);
  const [isAtBottom, setIsAtBottom] = useState(true);
  const [newMessagesCount, setNewMessagesCount] = useState(0);
  const [previousMessageCount, setPreviousMessageCount] = useState(0);
  const messagesContainerRef = React.useRef<HTMLDivElement>(null);
  const authorColorById = useMemo(() => {
    const map = new Map<string, string>();
    messages.forEach((message) => {
      if (message.authorColor) {
        map.set(message.id, message.authorColor);
      }
    });
    return map;
  }, [messages]);

  useEffect(() => {
    let filtered = messages;

    // Remove optimistic placeholders when a matching real server message exists.
    filtered = filtered.filter((msg, _, arr) => {
      if (!msg.optimistic) return true;

      // If there's a non-optimistic message with same content, reply target,
      // and userId, prefer the real one and drop this optimistic placeholder.
      const hasReal = arr.some((other) =>
        other !== msg &&
        !other.optimistic &&
        other.isCurrentUser &&
        other.userId === msg.userId &&
        other.content === msg.content &&
        ((other.replyTo?.id || '') === (msg.replyTo?.id || ''))
      );

      return !hasReal;
    });

    if (selectedPlatforms.length === 0) {
      setFilteredMessages(filtered);
    } else {
      filtered = filtered.filter((msg) => selectedPlatforms.includes(msg.platform));
      setFilteredMessages(filtered);
    }

    // Update new messages count when not at bottom
    if (!isAtBottom) {
      const newCount = filtered.length - previousMessageCount;
      if (newCount > 0) {
        setNewMessagesCount(newCount);
      }
    }
  }, [messages, selectedPlatforms, isAtBottom, previousMessageCount]);

  // Auto-scroll to bottom when messages change (only if user is at bottom)
  useEffect(() => {
    if (messagesContainerRef.current && isAtBottom) {
      messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
    }
  }, [filteredMessages, isAtBottom]);

  // Track scroll position
  useEffect(() => {
    const handleScroll = () => {
      if (messagesContainerRef.current) {
        const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
        // Consider user at bottom if within 50px of bottom
        const atBottom = scrollHeight - scrollTop - clientHeight < 50;
        setIsAtBottom(atBottom);

        // Reset new messages count when user scrolls back to bottom
        if (atBottom) {
          setNewMessagesCount(0);
          setPreviousMessageCount(filteredMessages.length);
        }
      }
    };

    const container = messagesContainerRef.current;
    if (container) {
      container.addEventListener('scroll', handleScroll);
      return () => container.removeEventListener('scroll', handleScroll);
    }
  }, [filteredMessages.length]);

  // Handle emote tooltip on hover
  useEffect(() => {
    const handleEmoteHover = (e: Event) => {
      const target = e.target as HTMLImageElement;

      if (!target.classList.contains('chat-emote')) return;

      if (e.type === 'mouseenter') {
        const tooltipUrl = target.getAttribute('data-tooltip-url');
        const emoteName = target.getAttribute('data-emote-name') || 'Emote';

        if (tooltipUrl) {
          const tooltip = document.createElement('div');
          tooltip.className = 'chat-emote-tooltip';
          tooltip.id = 'emote-tooltip';

          const img = document.createElement('img');
          img.src = tooltipUrl;
          img.alt = emoteName;
          tooltip.appendChild(img);

          const nameDiv = document.createElement('div');
          nameDiv.className = 'chat-emote-tooltip-name';
          nameDiv.textContent = emoteName;
          tooltip.appendChild(nameDiv);

          document.body.appendChild(tooltip);

          // Position tooltip near the mouse
          const rect = target.getBoundingClientRect();
          tooltip.style.left = (rect.left + window.scrollX) + 'px';
          tooltip.style.top = (rect.top + window.scrollY - tooltip.offsetHeight - 10) + 'px';
        }
      } else if (e.type === 'mouseleave') {
        const tooltip = document.getElementById('emote-tooltip');
        if (tooltip) {
          tooltip.remove();
        }
      }
    };

    const messagesContainer = messagesContainerRef.current;
    if (messagesContainer) {
      messagesContainer.addEventListener('mouseenter', handleEmoteHover, true);
      messagesContainer.addEventListener('mouseleave', handleEmoteHover, true);
    }

    return () => {
      if (messagesContainer) {
        messagesContainer.removeEventListener('mouseenter', handleEmoteHover, true);
        messagesContainer.removeEventListener('mouseleave', handleEmoteHover, true);
      }
    };
  }, []);


  // Helper to render message icon for special events
  const renderMessageIcon = (msg: ChatMessage) => {
    if (!msg.messageType) return null;

    const iconConfig: Record<string, { title: string; color: string }> = {
      cheer: { title: 'Cheer', color: '#FFB700' },
      subscription: { title: 'Subscription', color: '#9147FF' },
      resub: { title: 'Resub', color: '#9147FF' },
      subgift: { title: 'Subgift', color: '#9147FF' },
      redemption: { title: 'Channel Points Redemption', color: '#9147FF' },
    };

    const config = iconConfig[msg.messageType];
    if (!config) return null;

    let iconElement;
    switch (msg.messageType) {
      case 'cheer':
        iconElement = <GiHeartBeats size={16} />;
        break;
      case 'subscription':
        iconElement = <MdStars size={16} />;
        break;
      case 'resub':
        iconElement = <MdAutorenew size={16} />;
        break;
      case 'subgift':
        iconElement = <MdCardGiftcard size={16} />;
        break;
      case 'redemption':
        iconElement = <MdRedeem size={16} />;
        break;
      default:
        return null;
    }

    return (
      <span
        title={config.title}
        style={{
          marginRight: '6px',
          display: 'inline-flex',
          alignItems: 'center',
          color: config.color,
          filter: `drop-shadow(0 0 2px ${config.color})`,
        }}
      >
        {iconElement}
      </span>
    );
  };

  // Helper to render badges
  const renderBadges = (msg: ChatMessage) => {
    // Prefer detailed badge info if available (contains titles/descriptions)
    if (msg.badgeDetails && Object.keys(msg.badgeDetails).length > 0) {
      return (
        <div className="message-badges" style={{ display: 'flex', alignItems: 'center', marginRight: '4px', gap: '2px' }}>
          {Object.entries(msg.badgeDetails).map(([name, detail]) => (
            <img
              key={name}
              src={detail.url}
              alt={detail.title}
              className="badge"
              title={detail.title}
              loading="eager"
              style={{
                width: '18px',
                height: '18px',
                verticalAlign: 'middle'
              }}
            />
          ))}
        </div>
      );
    }

    // Fallback for platform-agnostic or historical badges
    if (!msg.badges || Object.keys(msg.badges).length === 0) return null;

    return (
      <div className="message-badges" style={{ display: 'flex', alignItems: 'center', marginRight: '4px', gap: '2px' }}>
        {Object.entries(msg.badges).map(([name, badgeUrl]) => {
          if (!badgeUrl) return null;

          return (
            <img
              key={`${name}`}
              src={badgeUrl}
              alt={name}
              className="badge"
              title={name}
              loading="eager"
              style={{
                width: '18px',
                height: '18px',
                verticalAlign: 'middle'
              }}
            />
          );
        })}
      </div>
    );
  };

  return (
    <div className="chat-display">
      <div className="chat-header">
        <div className="chat-header-content">
          {onToggleSidebar && (
            <button
              onClick={onToggleSidebar}
              className="sidebar-toggle-button"
              title={sidebarVisible ? 'Hide sidebar' : 'Show sidebar'}
            >
              {sidebarVisible ? '◀' : '▶'}
            </button>
          )}
          {!showStreamEmbed && onToggleStreamEmbed && (
            <button
              onClick={onToggleStreamEmbed}
              className="show-stream-button"
              title="Show stream embed"
            >
              Show Stream
            </button>
          )}
          <h2>
            {isStreamLive ? (
              <span className="status-badge-live">
                <span className="status-dot pulse" />
                LIVE
              </span>
            ) : (
              <span className="status-badge-offline">
                <span className="status-dot" />
                OFFLINE
              </span>
            )}
            <a
              href={`https://twitch.tv/${channelName}`}
              target="_blank"
              rel="noopener noreferrer"
              className="channel-link"
            >
              {channelDisplayName || channelName || 'Chat'}
            </a>
            {viewerCount !== undefined && viewerCount !== null && (
              <span className="viewer-count-display">
                <FaUsers size={14} /> {viewerCount.toLocaleString()}
              </span>
            )}
            {streamUptime && isStreamLive && (
              <span className="uptime-display">
                ({streamUptime})
              </span>
            )}
          </h2>
          {streamTitle && <span className="stream-title">{streamTitle}</span>}
        </div>
        <div className="chat-header-actions">
          {onRefreshEmotes && (
            <button
              onClick={onRefreshEmotes}
              disabled={isRefreshingEmotes}
              className="header-button"
              title={isRefreshingEmotes ? 'Reloading emotes...' : 'Reload all emotes (clears cache)'}
              style={{ display: 'flex', alignItems: 'center', gap: '6px' }}
            >
              <MdRefresh size={14} style={{ animation: isRefreshingEmotes ? 'spin 1s linear infinite' : 'none' }} />
              {isRefreshingEmotes ? 'Reloading...' : 'Reload Emotes'}
            </button>
          )}
          {isLoading && <span className="loading-indicator">●</span>}
        </div>
      </div>

      {unifiedChatSlot ? (
        unifiedChatSlot
      ) : (
        <div
          className="messages-container"
          ref={messagesContainerRef}
          style={{ '--chat-font-size': `${fontSize}px` } as React.CSSProperties}
        >
          {filteredMessages.length === 0 ? (
            <div className="no-messages">
              <p>No messages yet. Start chatting!</p>
            </div>
          ) : (
            filteredMessages.map((msg) => {
              const isMentioned = currentUserDisplayName && msg.content.includes(currentUserDisplayName);
              const messageClasses = [
                'message',
                msg.messageType || 'chat',
                msg.isPreloaded ? 'preloaded' : '',
                msg.isBot ? 'bot' : '',
                ((msg.mentionsUser || isMentioned) && !msg.isBot) ? 'mention' : ''
              ].filter(Boolean).join(' ');

              return (
                <div key={msg.id} className={messageClasses}>
                  {msg.replyTo && (
                    <div className="reply-info">
                      <span>response to{' '}
                        <span
                          style={{
                            color: authorColorById.get(msg.replyTo.id) || '#94a3b8',
                          }}
                        >
                          @{msg.replyTo.author}
                        </span>
                        {msg.replyTo.content && (
                          <>
                            {': '}
                            <span
                              className="reply-target-content"
                              dangerouslySetInnerHTML={{
                                __html: parseMessageWithEmotes(msg.replyTo.content)
                              }}
                            />
                          </>
                        )}
                      </span>

                    </div>
                  )}
                  <div className="message-single-line">
                    <span className="timestamp">
                      {msg.timestamp.toLocaleTimeString()}
                    </span>
                    {msg.authorAvatar && (
                      <img
                        src={msg.authorAvatar}
                        alt={msg.author}
                        className="avatar"
                      />
                    )}
                    {renderMessageIcon(msg)}
                    {renderBadges(msg)}
                    <a
                      href={`https://twitch.tv/${msg.author}`}
                      target="_blank"
                      rel="noopener noreferrer"
                      className={`author author-link ${msg.isCurrentUser ? 'self' : ''}`}
                      style={{
                        color: msg.isCurrentUser ? '#ffffff' : (msg.authorColor || '#e2e8f0'),
                      }}
                    >
                      {msg.author}
                    </a>
                    <span className="message-separator">:</span>
                    <span
                      className="message-text"
                      dangerouslySetInnerHTML={{
                        __html: parseMessageWithEmotes(msg.content, msg.emotes),
                      }}
                    />
                    <div className="message-actions">
                      {onReply && (
                        <button
                          onClick={() => onReply(msg)}
                          className="action-button"
                          title="Reply to this message"
                          style={{ display: 'flex', alignItems: 'center', gap: '4px' }}
                        >
                          <MdReply size={12} />
                        </button>
                      )}
                      <button
                        onClick={() => {
                          if (navigator.clipboard) {
                            navigator.clipboard.writeText(msg.content).then(() => {
                              onCopyMessage?.();
                            }).catch((err) => {
                              console.error('Failed to copy:', err);
                            });
                          } else {
                            // Fallback for environments without clipboard API
                            const textArea = document.createElement('textarea');
                            textArea.value = msg.content;
                            document.body.appendChild(textArea);
                            textArea.select();
                            try {
                              document.execCommand('copy');
                              onCopyMessage?.();
                            } catch (err) {
                              console.error('Failed to copy:', err);
                            }
                            document.body.removeChild(textArea);
                          }
                        }}
                        className="action-button"
                        title="Copy message"
                        style={{ display: 'flex', alignItems: 'center', gap: '4px' }}
                      >
                        <MdContentCopy size={12} />
                      </button>
                    </div>
                  </div>
                </div>
              );
            })
          )}
        </div>
      )}
      {!isAtBottom && !unifiedChatSlot && (
        <button
          onClick={() => {
            if (messagesContainerRef.current) {
              messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
              setIsAtBottom(true);
              setNewMessagesCount(0);
              setPreviousMessageCount(filteredMessages.length);
            }
          }}
          className="go-to-bottom-button"
          title="Go to latest messages"
        >
          {newMessagesCount > 0 ? `New Messages (${newMessagesCount})` : 'New Messages'}
        </button>
      )}
    </div>
  );
}

export default memo(ChatDisplay);
