/** 
// this is needed for Tauri to work properly!
const { invoke } = window.__TAURI__.core;
//

let greetInputEl;
let greetMsgEl;

async function greet() {
  // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
  greetMsgEl.textContent = await invoke("greet", { name: greetInputEl.value });
}

window.addEventListener("DOMContentLoaded", () => {
  greetInputEl = document.querySelector("#greet-input");
  greetMsgEl = document.querySelector("#greet-msg");
  document.querySelector("#greet-form").addEventListener("submit", (e) => {
    e.preventDefault();
    greet();
  });
});
*/

// UI State Management
const uiState = {
  connected: false,
  activeTab: null,
  channels: [],
  collapsedSidebar: false,
  collapsedPeopleSidebar: false,
  userColors: new Map(),
  currentUser: 'IRCDUser',
  channelUsers: new Map(), // Map<channel, Set<user>>
  channelMessages: new Map(), // Map<channel, Array<{type, sender, content, timestamp, html}>>
  peopleSearchQuery: '', // Current search query for people list
  virtualScrollState: {
    startIndex: 0,
    endIndex: 50, // Initial visible range
    itemHeight: 30, // Approximate height of each people item (padding + margin + content)
    containerHeight: 0
  },
  filteredUsers: [] // Filtered users list for virtual scrolling
};

// DOM Elements
const sidebar = document.getElementById('channels');
const sidebarResizeHandle = document.getElementById('sidebarResizeHandle');
const toggleSidebarBtn = document.getElementById('toggleSidebar');
const peopleSidebar = document.getElementById('peopleSidebar');
const peopleSidebarResizeHandle = document.getElementById('peopleSidebarResizeHandle');
const togglePeopleSidebarBtn = document.getElementById('togglePeopleSidebar');
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
const joinBtn = document.getElementById('joinBtn');
const partBtn = document.getElementById('partBtn');
const sendBtn = document.getElementById('sendBtn');
const statusDot = document.getElementById('statusDot');
const statusText = document.getElementById('status');
const tabBar = document.getElementById('tabBar');
const messagesContainer = document.getElementById('messages');
const channelList = document.getElementById('channelList');
const peopleList = document.getElementById('peopleList');
const peopleListContainer = document.getElementById('peopleListContainer');
const peopleListSpacer = document.getElementById('peopleListSpacer');
const peopleSearchInput = document.getElementById('peopleSearch');
const messageInput = document.getElementById('messageInput');
const channelInput = document.getElementById('newChannel');
const commandSuggestions = document.getElementById('commandSuggestions');

// Color palette for users
const userColors = [
  '#4b82ff', '#ff6b6b', '#7edba5', '#ffa94d', 
  '#cc5de8', '#20c997', '#f06595', '#748ffc',
  '#ffd43b', '#69db7c', '#a9e34b', '#ff8787'
];

// Initialize UI
function initUI() {
  // Set current user from nickname input
  const nicknameInput = document.getElementById('nickname');
  uiState.currentUser = nicknameInput.value;
  nicknameInput.addEventListener('change', (e) => {
    uiState.currentUser = e.target.value;
  });

  // Add event listeners
  toggleSidebarBtn.addEventListener('click', toggleSidebar);
  togglePeopleSidebarBtn.addEventListener('click', togglePeopleSidebar);
  connectBtn.addEventListener('click', handleConnect);
  disconnectBtn.addEventListener('click', handleDisconnect);
  joinBtn.addEventListener('click', handleJoin);
  partBtn.addEventListener('click', handlePart);
  sendBtn.addEventListener('click', handleSend);
  messageInput.addEventListener('keydown', handleMessageInput);
  channelInput.addEventListener('keydown', handleChannelInput);
  peopleSearchInput.addEventListener('input', handlePeopleSearch);
  peopleListContainer.addEventListener('scroll', handlePeopleListScroll);
  
  // Set up sidebar resizing
  setupSidebarResize();
  setupPeopleSidebarResize();
  
  // Initialize virtual scroll container height
  updateVirtualScrollContainerHeight();
  
  // Watch for container resize
  if (peopleListContainer && ResizeObserver) {
    const resizeObserver = new ResizeObserver(() => {
      updateVirtualScrollContainerHeight();
    });
    resizeObserver.observe(peopleListContainer);
  }
  
  // Set active tab
  setActiveTab('welcome');
}

// Setup sidebar resizing
function setupSidebarResize() {
  let isResizing = false;
  
  sidebarResizeHandle.addEventListener('mousedown', (e) => {
    isResizing = true;
    sidebarResizeHandle.classList.add('resizing');
    document.body.style.cursor = 'col-resize';
    e.preventDefault();
  });
  
  document.addEventListener('mousemove', (e) => {
    if (!isResizing) return;
    
    const newWidth = e.clientX;
    if (newWidth > 200 && newWidth < 500) {
      sidebar.style.width = `${newWidth}px`;
    }
  });
  
  document.addEventListener('mouseup', () => {
    if (isResizing) {
      isResizing = false;
      sidebarResizeHandle.classList.remove('resizing');
      document.body.style.cursor = '';
    }
  });
}

// Setup people sidebar resizing
function setupPeopleSidebarResize() {
  let isResizing = false;
  
  peopleSidebarResizeHandle.addEventListener('mousedown', (e) => {
    isResizing = true;
    peopleSidebarResizeHandle.classList.add('resizing');
    document.body.style.cursor = 'col-resize';
    e.preventDefault();
  });
  
  document.addEventListener('mousemove', (e) => {
    if (!isResizing) return;
    
    const newWidth = window.innerWidth - e.clientX;
    if (newWidth > 200 && newWidth < 500) {
      peopleSidebar.style.width = `${newWidth}px`;
    }
  });
  
  document.addEventListener('mouseup', () => {
    if (isResizing) {
      isResizing = false;
      peopleSidebarResizeHandle.classList.remove('resizing');
      document.body.style.cursor = '';
    }
  });
}

// Toggle sidebar
function toggleSidebar() {
  uiState.collapsedSidebar = !uiState.collapsedSidebar;
  sidebar.classList.toggle('collapsed', uiState.collapsedSidebar);
  
  // Update toggle button icon
  const icon = toggleSidebarBtn.querySelector('svg');
  if (uiState.collapsedSidebar) {
    icon.innerHTML = '<path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
  } else {
    icon.innerHTML = '<path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
  }
}

// Toggle people sidebar
function togglePeopleSidebar() {
  uiState.collapsedPeopleSidebar = !uiState.collapsedPeopleSidebar;
  peopleSidebar.classList.toggle('collapsed', uiState.collapsedPeopleSidebar);
  
  // Update toggle button icon
  const icon = togglePeopleSidebarBtn.querySelector('svg');
  if (uiState.collapsedPeopleSidebar) {
    icon.innerHTML = '<path d="M15 18L9 12L15 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
  } else {
    icon.innerHTML = '<path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>';
  }
}

// Get color for a user
function getUserColor(username) {
  if (!uiState.userColors.has(username)) {
    // Assign a color from the palette based on username hash
    const hash = username.split('').reduce((a, b) => {
      a = ((a << 5) - a) + b.charCodeAt(0);
      return a & a;
    }, 0);
    const colorIndex = Math.abs(hash) % userColors.length;
    uiState.userColors.set(username, userColors[colorIndex]);
  }
  return uiState.userColors.get(username);
}

// Connection handlers
function handleConnect() {
  uiState.connected = true;
  updateConnectionStatus();
  addSystemMessage(`Connecting to ${document.getElementById('server').value}...`);
  
  // Simulate connection
  setTimeout(() => {
    addSystemMessage('Connected to server!');
  }, 1000);
}

function handleDisconnect() {
  uiState.connected = false;
  updateConnectionStatus();
  addSystemMessage('Disconnected from server.');
}

function updateConnectionStatus() {
  if (uiState.connected) {
    statusDot.classList.add('online');
    statusText.textContent = 'Connected';
    connectBtn.disabled = true;
    disconnectBtn.disabled = false;
  } else {
    statusDot.classList.remove('online');
    statusText.textContent = 'Disconnected';
    connectBtn.disabled = false;
    disconnectBtn.disabled = true;
  }
}

// Channel handlers
function handleJoin() {
  let channel = channelInput.value.trim();
  if (channel && !channel.startsWith('#')) {
    channel = '#' + channel;
    channelInput.value = channel;
  }
  
  if (channel) {
    addChannel(channel);
    channelInput.value = '';
    addSystemMessage(`Joined ${channel}`);
  }
}

function handlePart() {
  if (uiState.activeTab && uiState.activeTab !== 'welcome') {
    const channel = uiState.activeTab;
    removeChannel(channel);
    addSystemMessage(`Left ${channel}`);
  }
}

function addChannel(name) {
  // Normalize channel name to always start with #
  let normalizedName = name;
  if (!normalizedName.startsWith('#')) {
    normalizedName = '#' + normalizedName;
  }
  
  if (!uiState.channels.includes(normalizedName)) {
    uiState.channels.push(normalizedName);
    
    // Add to channel list (async DOM update)
    requestAnimationFrame(() => {
      const channelItem = document.createElement('div');
      channelItem.className = 'channel-item';
      channelItem.innerHTML = `
        <div class="channel-icon">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M5 9C5 5.13401 8.13401 2 12 2C15.866 2 19 5.13401 19 9C19 10.933 18.2165 12.683 16.8569 14.0002C16.8569 14.0002 16.5 14.5 15.5 15.5C14.5 16.5 13 18 13 18L12 19L11 18C11 18 9.5 16.5 8.5 15.5C7.5 14.5 7.14314 14.0002 7.14314 14.0002C5.78354 12.683 5 10.933 5 9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M9 9H15M9 12H15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
          </svg>
        </div>
        <div class="channel-name">${escapeHtml(normalizedName)}</div>
      `;
      channelItem.addEventListener('click', () => setActiveTab(normalizedName));
      channelList.appendChild(channelItem);
    });
    
    // Add tab (async)
    requestAnimationFrame(() => addTab(normalizedName));
    
    // Initialize message storage for this channel
    if (!uiState.channelMessages.has(normalizedName)) {
      uiState.channelMessages.set(normalizedName, []);
    }
    
    // Auto-join the channel when connected
    if (uiState.connected) {
      invoke('join_channel', { channel: normalizedName }).catch(e => {
        addSystemMessage(`Failed to join ${normalizedName}: ${e}`);
      });
    }
  }
}

function removeChannel(name) {
  const index = uiState.channels.indexOf(name);
  if (index > -1) {
    uiState.channels.splice(index, 1);
    
    // Remove from channel list
    const channelItems = channelList.querySelectorAll('.channel-item');
    channelItems.forEach(item => {
      if (item.querySelector('.channel-name').textContent === name) {
        item.remove();
      }
    });
    
    // Clear users for this channel
    clearChannelUsers(name);
    
    // Clear messages for this channel (optional - you might want to keep them)
    // uiState.channelMessages.delete(name);
    
    // Remove tab
    removeTab(name);
    
    // Auto-leave the channel when connected
    if (uiState.connected) {
      invoke('part_channel', { channel: name }).catch(e => {
        addSystemMessage(`Failed to leave ${name}: ${e}`);
      });
    }
  }
}

// Tab management
function addTab(name) {
  // Normalize channel name
  let normalizedName = name;
  if (name !== 'welcome' && !name.startsWith('#')) {
    normalizedName = '#' + name;
  }
  
  const tab = document.createElement('div');
  tab.className = 'tab';
  tab.dataset.tab = normalizedName;
  tab.innerHTML = `
    <span>${normalizedName}</span>
    <span class="tab-close">&times;</span>
  `;
  
  tab.addEventListener('click', (e) => {
    if (e.target.classList.contains('tab-close')) {
      removeTab(normalizedName);
    } else {
      setActiveTab(normalizedName);
    }
  });
  
  tabBar.appendChild(tab);
  setActiveTab(normalizedName);
}

function removeTab(name) {
  const tab = tabBar.querySelector(`[data-tab="${name}"]`);
  if (tab) {
    tab.remove();
    
    // If this was the active tab, switch to another
    if (uiState.activeTab === name) {
      if (uiState.channels.length > 0) {
        setActiveTab(uiState.channels[0]);
      } else {
        setActiveTab('welcome');
      }
    }
  }
}

function setActiveTab(name) {
  // Normalize channel name to ensure consistency
  let normalizedName = name;
  if (name !== 'welcome' && !name.startsWith('#')) {
    normalizedName = '#' + name;
  }
  
  uiState.activeTab = normalizedName;
  
  // Update tabs (async)
  requestAnimationFrame(() => {
    const tabs = tabBar.querySelectorAll('.tab');
    tabs.forEach(tab => {
      // Compare with both normalized and original name
      tab.classList.toggle('active', tab.dataset.tab === normalizedName || tab.dataset.tab === name);
    });
  });
  
  // Update channels (async)
  requestAnimationFrame(() => {
    const channelItems = channelList.querySelectorAll('.channel-item');
    channelItems.forEach(item => {
      const channelName = item.querySelector('.channel-name').textContent;
      item.classList.toggle('active', channelName === normalizedName || channelName === name);
    });
  });
  
  // Update people list for the active channel (async)
  updatePeopleList(normalizedName);
  
  // Update messages (async)
  requestAnimationFrame(() => {
    updateMessagesForTab(normalizedName);
  });
}

function updateMessagesForTab(name) {
  // Clear messages
  messagesContainer.innerHTML = '';
  
  // Ensure channel name format is correct
  let channelKey = name;
  if (name !== 'welcome' && !name.startsWith('#')) {
    channelKey = '#' + name;
  }
  
  // Load stored messages from RAM
  const storedMessages = uiState.channelMessages.get(channelKey);
  if (storedMessages && storedMessages.length > 0) {
    // Restore all stored messages (only once, not duplicated)
    requestAnimationFrame(() => {
      // Use a Set to track displayed messages and prevent duplicates
      const displayedHashes = new Set();
      
      storedMessages.forEach(msg => {
        // Create a hash to detect duplicates
        const msgHash = `${msg.type}-${msg.timestamp}-${msg.content.substring(0, 50)}`;
        
        if (displayedHashes.has(msgHash)) {
          return; // Skip duplicate
        }
        displayedHashes.add(msgHash);
        
        if (msg.html) {
          // For IRC messages, the HTML is the full formatted content
          // The HTML from backend is a string of spans, so we wrap it in a div
          const ircMessage = document.createElement('div');
          ircMessage.className = 'irc-message';
          
          // Use the stored HTML (which is the full formatted content from backend)
          // If raw exists, prefer it, otherwise use html
          const htmlContent = msg.raw || msg.html;
          ircMessage.innerHTML = htmlContent;
          
          messagesContainer.appendChild(ircMessage);
        } else if (msg.type === 'message') {
          // Recreate message element if HTML not stored
          const messageLine = document.createElement('div');
          messageLine.className = 'message-line';
          
          const senderElement = document.createElement('div');
          senderElement.className = `message-sender ${msg.isUser ? 'you' : ''}`;
          senderElement.textContent = msg.isUser ? `${msg.sender} (You):` : `${msg.sender}:`;
          senderElement.style.color = msg.isUser ? '' : getUserColor(msg.sender);
          
          const contentElement = document.createElement('div');
          contentElement.className = 'message-content';
          contentElement.textContent = msg.content;
          
          messageLine.appendChild(senderElement);
          messageLine.appendChild(contentElement);
          messagesContainer.appendChild(messageLine);
        } else if (msg.type === 'system') {
          const systemMessage = document.createElement('div');
          systemMessage.className = 'system-message';
          systemMessage.textContent = msg.content;
          messagesContainer.appendChild(systemMessage);
        }
      });
      scrollToBottom();
    });
  } else {
    // Add welcome messages for new channels (only if no stored messages)
    if (name === 'welcome') {
      // Don't store welcome messages, just display
      requestAnimationFrame(() => {
        const welcomeMsg = document.createElement('div');
        welcomeMsg.className = 'system-message';
        welcomeMsg.textContent = 'IRCD - Welcome! SystemTime: ' + new Date().toLocaleString();
        messagesContainer.appendChild(welcomeMsg);
      });
    } else if (channelKey !== 'welcome') {
      // Only add welcome message if channel has no messages
      addSystemMessage(`Welcome to ${channelKey}!`);
      addSystemMessage('This is the beginning of the channel.');
    }
  }
}

// Message handling
function handleSend() {
  const message = messageInput.value.trim();
  if (message) {
    if (message.startsWith('/')) {
      handleCommand(message);
    } else {
      const target = uiState.activeTab;
      if (target && target !== 'welcome') {
        addMessage(uiState.currentUser, message, true);
        // Send the message to the server
        invoke('send_message', { target, message }).catch(e => {
          addSystemMessage(`Failed to send message: ${e}`);
        });
      } else {
        addSystemMessage('Join a channel to send messages.');
      }
    }
    messageInput.value = '';
  }
}

function handleCommand(command) {
  addSystemMessage(`Command: ${command}`);
  // Handle specific commands here
  if (command.startsWith('/join ')) {
    const channel = command.split(' ')[1];
    if (channel) {
      addChannel(channel);
    }
  }
}

function addMessage(sender, content, isUser = false) {
  const channel = uiState.activeTab;
  if (!channel || channel === 'welcome') return;
  
  // Normalize channel name
  let channelKey = channel;
  if (!channelKey.startsWith('#')) {
    channelKey = '#' + channelKey;
  }
  
  // Store message in RAM - ALWAYS store
  if (!uiState.channelMessages.has(channelKey)) {
    uiState.channelMessages.set(channelKey, []);
  }
  
  // Use requestAnimationFrame for async DOM updates
  requestAnimationFrame(() => {
    const messageLine = document.createElement('div');
    messageLine.className = 'message-line';
    
    const senderElement = document.createElement('div');
    senderElement.className = `message-sender ${isUser ? 'you' : ''}`;
    senderElement.textContent = isUser ? `${sender} (You):` : `${sender}:`;
    senderElement.style.color = isUser ? '' : getUserColor(sender);
    
    const contentElement = document.createElement('div');
    contentElement.className = 'message-content';
    contentElement.textContent = content;
    
    messageLine.appendChild(senderElement);
    messageLine.appendChild(contentElement);
    
    // Store FULL message data with HTML
    const messageData = {
      type: 'message',
      sender,
      content,
      isUser,
      timestamp: Date.now(),
      html: messageLine.outerHTML, // Full HTML content
      raw: messageLine.outerHTML, // Keep raw HTML
      formatted: true // Mark as formatted
    };
    
    uiState.channelMessages.get(channelKey).push(messageData);
    console.log(`[STORE] Stored FULL user message in ${channelKey} (${content.substring(0, 50)}...)`);
    
    // Update activeTab to normalized name for consistency
    if (uiState.activeTab !== channelKey) {
      uiState.activeTab = channelKey;
    }
    
    messagesContainer.appendChild(messageLine);
    scrollToBottom();
  });
}

function addSystemMessage(content) {
  const channel = uiState.activeTab;
  if (!channel || channel === 'welcome') return;
  
  // Normalize channel name
  let channelKey = channel;
  if (!channelKey.startsWith('#')) {
    channelKey = '#' + channelKey;
  }
  
  // Store message in RAM - ALWAYS store
  if (!uiState.channelMessages.has(channelKey)) {
    uiState.channelMessages.set(channelKey, []);
  }
  
  // Use requestAnimationFrame for async DOM updates
  requestAnimationFrame(() => {
    const systemMessage = document.createElement('div');
    systemMessage.className = 'system-message';
    systemMessage.textContent = content;
    
    // Store FULL message data with HTML
    const messageData = {
      type: 'system',
      sender: null,
      content,
      isUser: false,
      timestamp: Date.now(),
      html: systemMessage.outerHTML, // Full HTML content
      raw: systemMessage.outerHTML, // Keep raw HTML
      formatted: true // Mark as formatted
    };
    
    uiState.channelMessages.get(channelKey).push(messageData);
    console.log(`[STORE] Stored FULL system message in ${channelKey} (${content.substring(0, 50)}...)`);
    
    // Update activeTab to normalized name for consistency
    if (uiState.activeTab !== channelKey) {
      uiState.activeTab = channelKey;
    }
    
    messagesContainer.appendChild(systemMessage);
    scrollToBottom();
  });
}

function addIRCMessage(content) {
  // Parse the message to determine which channel it belongs to
  let targetChannel = null;
  let joinMatch = null;
  let partMatch = null;
  
  // Extract plain text for checking
  const plainText = content.replace(/<[^>]*>/g, '');
  
  // Check if this is a server notice (starts with server name, no channel)
  const isServerNotice = /^[a-zA-Z0-9.-]+\s+\[NOTICE\]/.test(plainText) || 
                         /^[a-zA-Z0-9.-]+\s+NOTICE/.test(plainText);
  
  // Try to extract channel from PRIVMSG
  // PRIVMSG format: <sender> → <channel>: <message>
  const privmsgMatch = content.match(/→\s*<span[^>]*>([^<]+)<\/span><span[^>]*>:\s*<\/span>/);
  if (privmsgMatch) {
    targetChannel = privmsgMatch[1].trim();
  }
  
  // NOTICE format: [NOTICE] <sender> → <target>: <message>
  // Only if target is a channel (starts with #)
  const noticeMatch = content.match(/\[NOTICE\].*?→\s*<span[^>]*>([^<]+)<\/span><span[^>]*>:\s*<\/span>/);
  if (noticeMatch) {
    const target = noticeMatch[1].trim();
    // Only treat as channel message if target starts with #
    if (target.startsWith('#')) {
      targetChannel = target;
    } else if (!isServerNotice) {
      // If it's a user notice, check if we're in a PM (future feature)
      // For now, skip storing user notices
    }
  }
  
  // JOIN format: <sender> joined <channel>
  joinMatch = content.match(/joined\s*<span[^>]*>([^<]+)<\/span>/);
  if (joinMatch) {
    targetChannel = joinMatch[1].trim();
    // Extract sender name from the beginning of the message
    const senderMatch = plainText.match(/^([^\s]+)\s+joined/);
    if (senderMatch) {
      const sender = senderMatch[1];
      console.log(`[JOIN] ${sender} joined ${targetChannel}`);
    }
  }
  
  // PART format: <sender> left <channel>
  partMatch = content.match(/left\s*<span[^>]*>([^<]+)<\/span>/);
  if (partMatch) {
    targetChannel = partMatch[1].trim();
    // Extract sender name from the beginning of the message
    const senderMatch = plainText.match(/^([^\s]+)\s+left/);
    if (senderMatch) {
      const sender = senderMatch[1];
      console.log(`[PART] ${sender} left ${targetChannel}`);
    }
  }
  
  // QUIT format: <sender> quit (reason)
  const quitMatch = plainText.match(/^([^\s]+)\s+quit/);
  if (quitMatch) {
    // QUIT messages don't have a channel, but we should still display them
    const sender = quitMatch[1];
    console.log(`[QUIT] ${sender} quit`);
  }
  
  // NICK format: <sender> is now known as <newnick>
  const nickMatch = plainText.match(/^([^\s]+)\s+is now known as\s+([^\s]+)/);
  if (nickMatch) {
    const sender = nickMatch[1];
    const newNick = nickMatch[2];
    console.log(`[NICK] ${sender} is now known as ${newNick}`);
  }
  
  // NAMES format: [NAMES] <channel>:
  const namesMatch = content.match(/\[NAMES\]\s*<\/span>\s*<span[^>]*>([^<]+)<\/span>/);
  if (namesMatch) {
    targetChannel = namesMatch[1].trim();
  }
  
  // Normalize channel name
  if (targetChannel && !targetChannel.startsWith('#')) {
    targetChannel = '#' + targetChannel;
  }
  
  // Normalize active channel for comparison
  let activeChannel = uiState.activeTab;
  if (activeChannel && activeChannel !== 'welcome' && !activeChannel.startsWith('#')) {
    activeChannel = '#' + activeChannel;
  }
  
  // Determine where to store the message - SIMPLE AND RELIABLE
  const isJoinOrPart = joinMatch || partMatch;
  
  // Always store in active channel (where user is viewing)
  // This ensures all messages seen by the user are stored
  let storeChannel = activeChannel || 'welcome';
  
  // If message has a specific target channel (PRIVMSG, JOIN, PART, etc.), also store there
  // But primary storage is always the active channel
  if (targetChannel && targetChannel.startsWith('#')) {
    // Store in both the target channel AND the active channel
    // This way messages are available when switching channels
    const channelsToStore = [storeChannel, targetChannel];
    
    channelsToStore.forEach(ch => {
      if (ch && ch !== 'welcome') {
        if (!uiState.channelMessages.has(ch)) {
          uiState.channelMessages.set(ch, []);
        }
        
        const existingMessages = uiState.channelMessages.get(ch);
        const now = Date.now();
        const duplicateWindow = isJoinOrPart ? 5000 : 2000;
        
        // Check for duplicates
        const isDuplicate = existingMessages.some(msg => 
          msg.type === 'irc' && 
          msg.content === plainText && 
          Math.abs(msg.timestamp - now) < duplicateWindow
        );
        
        if (!isDuplicate) {
          const messageData = {
            type: 'irc',
            sender: null,
            content: plainText,
            isUser: false,
            timestamp: now,
            html: content, // Full HTML content
            raw: content, // Keep raw HTML
            formatted: true // Mark as formatted
          };
          
          existingMessages.push(messageData);
          console.log(`[STORE] Stored FULL message in ${ch} (${plainText.substring(0, 50)}...)`);
        }
      }
    });
  } else {
    // No target channel - store only in active channel
    if (storeChannel && storeChannel !== 'welcome') {
      if (!uiState.channelMessages.has(storeChannel)) {
        uiState.channelMessages.set(storeChannel, []);
      }
      
      const existingMessages = uiState.channelMessages.get(storeChannel);
      const now = Date.now();
      const duplicateWindow = isJoinOrPart ? 5000 : 2000;
      
      const isDuplicate = existingMessages.some(msg => 
        msg.type === 'irc' && 
        msg.content === plainText && 
        Math.abs(msg.timestamp - now) < duplicateWindow
      );
      
      if (!isDuplicate) {
        const messageData = {
          type: 'irc',
          sender: null,
          content: plainText,
          isUser: false,
          timestamp: now,
          html: content, // Full HTML content
          raw: content, // Keep raw HTML
          formatted: true // Mark as formatted
        };
        
        existingMessages.push(messageData);
        console.log(`[STORE] Stored FULL message in ${storeChannel} (no target channel) (${plainText.substring(0, 50)}...)`);
      }
    }
  }
  
  // Display ALL messages in the active channel - no filtering
  // Always display, regardless of target channel
  requestAnimationFrame(() => {
    const ircMessage = document.createElement('div');
    ircMessage.className = 'irc-message';
    ircMessage.innerHTML = content; // Use innerHTML to render HTML formatting
    
    messagesContainer.appendChild(ircMessage);
    scrollToBottom();
  });
}

function scrollToBottom() {
  messagesContainer.scrollTop = messagesContainer.scrollHeight;
}

// Input handlers
function handleMessageInput(e) {
  if (e.key === 'Enter') {
    handleSend();
  }
}

function handleChannelInput(e) {
  if (e.key === 'Enter') {
    handleJoin();
  }
}

// Format IRC messages
function formatIRCMessage(message) {
  try {
    // Parse the message object from Tauri
    if (typeof message === 'string') {
      return message;
    }
    
    // Handle different message types
    if (message.command) {
      const command = message.command;
      
      // Handle PRIVMSG (regular messages)
      if (command === 'PRIVMSG' && message.params && message.params.length >= 2) {
        const sender = message.prefix ? extractNickname(message.prefix) : 'Unknown';
        const target = message.params[0];
        const content = message.params[1];
        
        // Check if this message is for the active tab
        if (target === uiState.activeTab || (target === uiState.currentUser && uiState.activeTab === sender)) {
          addMessage(sender, content);
        }
        return `${sender} -> ${target}: ${content}`;
      }
      
      // Handle JOIN
      if (command === 'JOIN' && message.params && message.params.length >= 1) {
        const sender = message.prefix ? extractNickname(message.prefix) : 'Unknown';
        const channel = message.params[0];
        
        if (sender === uiState.currentUser) {
          addSystemMessage(`You joined ${channel}`);
          if (!uiState.channels.includes(channel)) {
            addChannel(channel);
          }
        } else {
          addSystemMessage(`${sender} joined ${channel}`);
        }
        return `${sender} joined ${channel}`;
      }
      
      // Handle PART
      if (command === 'PART' && message.params && message.params.length >= 1) {
        const sender = message.prefix ? extractNickname(message.prefix) : 'Unknown';
        const channel = message.params[0];
        const reason = message.params[1] || '';
        
        if (sender === uiState.currentUser) {
          addSystemMessage(`You left ${channel}${reason ? `: ${reason}` : ''}`);
          removeChannel(channel);
        } else {
          addSystemMessage(`${sender} left ${channel}${reason ? `: ${reason}` : ''}`);
        }
        return `${sender} left ${channel}`;
      }
      
      // Handle server responses
      if (typeof command === 'object' && command.Response) {
        const [code, ...params] = command.Response;
        return `[${code}] ${params.join(' ')}`;
      }
      
      // Handle raw commands
      if (typeof command === 'object' && command.Raw) {
        const [code, ...params] = command.Raw;
        return `[RAW ${code}] ${params.join(' ')}`;
      }
      
      // Fallback: stringify the message
      return JSON.stringify(message);
    }
    
    return String(message);
  } catch (e) {
    console.error('Error formatting IRC message:', e);
    return String(message);
  }
}

function extractNickname(prefix) {
  if (typeof prefix === 'string') {
    return prefix.split('!')[0];
  }
  if (prefix && prefix.Nickname) {
    return prefix.Nickname[0];
  }
  if (prefix && prefix.ServerName) {
    return prefix.ServerName;
  }
  return 'Unknown';
}

// People list management with virtual scrolling and search
function updatePeopleList(channel) {
  // Only show people for channels (not welcome tab)
  if (channel === 'welcome' || !channel.startsWith('#')) {
    if (peopleList) peopleList.innerHTML = '';
    if (peopleListSpacer) peopleListSpacer.style.height = '0px';
    uiState.filteredUsers = [];
    return;
  }
  
  // Get users for this channel (stored in RAM)
  const users = uiState.channelUsers.get(channel);
  if (!users || users.size === 0) {
    if (peopleList) peopleList.innerHTML = '';
    if (peopleListSpacer) peopleListSpacer.style.height = '0px';
    uiState.filteredUsers = [];
    return;
  }
  
  // Sort and filter users (all stored in RAM, not DOM)
  setTimeout(() => {
    let sortedUsers = Array.from(users).sort((a, b) => {
      const aIsOp = a.startsWith('@');
      const bIsOp = b.startsWith('@');
      const aIsVoiced = a.startsWith('+');
      const bIsVoiced = b.startsWith('+');
      
      if (aIsOp && !bIsOp) return -1;
      if (!aIsOp && bIsOp) return 1;
      if (aIsVoiced && !bIsVoiced) return -1;
      if (!aIsVoiced && bIsVoiced) return 1;
      return a.localeCompare(b, undefined, { sensitivity: 'base' });
    });
    
    // Apply search filter
    const searchQuery = uiState.peopleSearchQuery.toLowerCase();
    if (searchQuery) {
      sortedUsers = sortedUsers.filter(user => {
        const displayName = (user.startsWith('@') || user.startsWith('+')) 
          ? user.substring(1).toLowerCase() 
          : user.toLowerCase();
        return displayName.includes(searchQuery);
      });
    }
    
    // Store filtered list for virtual scrolling (in RAM)
    uiState.filteredUsers = sortedUsers;
    
    // Reset scroll position when filtering
    if (searchQuery && peopleListContainer) {
      peopleListContainer.scrollTop = 0;
    }
    
    // Update virtual scroll - only renders visible items
    renderVisibleUsers();
  }, 0);
}

function renderVisibleUsers() {
  if (!uiState.filteredUsers || !peopleListContainer) return;
  
  const { itemHeight } = uiState.virtualScrollState;
  let containerHeight = uiState.virtualScrollState.containerHeight;
  
  // Get container height if not set
  if (!containerHeight || containerHeight === 0) {
    containerHeight = peopleListContainer.clientHeight;
    if (containerHeight === 0) {
      // Container not ready, try again later
      setTimeout(() => renderVisibleUsers(), 50);
      return;
    }
    uiState.virtualScrollState.containerHeight = containerHeight;
  }
  
  const scrollTop = peopleListContainer.scrollTop || 0;
  const totalItems = uiState.filteredUsers.length;
  
  // Calculate visible range with buffer
  const buffer = 10; // Render 10 extra items above and below for smooth scrolling
  const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
  const visibleCount = Math.ceil(containerHeight / itemHeight) + (buffer * 2);
  const endIndex = Math.min(totalItems, startIndex + visibleCount);
  
  uiState.virtualScrollState.startIndex = startIndex;
  uiState.virtualScrollState.endIndex = endIndex;
  
  // Update spacer height for items before visible range
  const topSpacerHeight = startIndex * itemHeight;
  if (peopleListSpacer) {
    peopleListSpacer.style.height = `${topSpacerHeight}px`;
  }
  
  // Set total height for proper scrolling
  const totalHeight = totalItems * itemHeight;
  if (peopleList) {
    peopleList.style.minHeight = `${totalHeight}px`;
  }
  
  // Clear and render only visible items
  requestAnimationFrame(() => {
    if (!peopleList) return;
    
    peopleList.innerHTML = '';
    const fragment = document.createDocumentFragment();
    
    for (let i = startIndex; i < endIndex; i++) {
      const user = uiState.filteredUsers[i];
      const peopleItem = createPeopleItem(user);
      fragment.appendChild(peopleItem);
    }
    
    peopleList.appendChild(fragment);
  });
}

function createPeopleItem(user) {
  const peopleItem = document.createElement('div');
  peopleItem.className = 'people-item';
  
  let prefix = '';
  let displayName = user;
  let iconColor = 'currentColor';
  
  if (user.startsWith('@')) {
    peopleItem.classList.add('op');
    prefix = '@';
    displayName = user.substring(1);
    iconColor = '#ff5f87';
  } else if (user.startsWith('+')) {
    peopleItem.classList.add('voiced');
    prefix = '+';
    displayName = user.substring(1);
    iconColor = '#5af78e';
  }
  
  peopleItem.innerHTML = `
    <div class="people-icon">
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <circle cx="12" cy="7" r="4" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    </div>
    ${prefix ? `<span class="people-prefix">${prefix}</span>` : '<span class="people-prefix"></span>'}
    <span class="people-name">${escapeHtml(displayName)}</span>
  `;
  
  return peopleItem;
}

function handlePeopleSearch(e) {
  uiState.peopleSearchQuery = e.target.value;
  const channel = uiState.activeTab;
  if (channel) {
    updatePeopleList(channel);
  }
}

function handlePeopleListScroll() {
  requestAnimationFrame(() => {
    renderVisibleUsers();
  });
}

function updateVirtualScrollContainerHeight() {
  requestAnimationFrame(() => {
    if (peopleListContainer) {
      uiState.virtualScrollState.containerHeight = peopleListContainer.clientHeight;
      renderVisibleUsers();
    }
  });
}

function parseNamesMessage(channel, usersStr) {
  if (!channel || !usersStr) return;
  
  // Process parsing asynchronously
  setTimeout(() => {
    // Initialize users set for this channel if it doesn't exist
    // Note: We accumulate users from multiple NAMES messages until ENDOFNAMES
    // Users are stored in RAM, not DOM
    if (!uiState.channelUsers.has(channel)) {
      uiState.channelUsers.set(channel, new Set());
    }
    
    const users = usersStr.trim().split(/\s+/).filter(u => u && u.trim().length > 0);
    const channelUsers = uiState.channelUsers.get(channel);
    
    // Add all users from this NAMES message to RAM
    users.forEach(user => {
      const trimmed = user.trim();
      if (trimmed) {
        channelUsers.add(trimmed);
      }
    });
    
    // Update the people list if this is the active channel (async)
    // This will use virtual scrolling to only render visible users
    if (uiState.activeTab === channel) {
      updatePeopleList(channel);
    }
  }, 0);
}

function clearChannelUsers(channel) {
  uiState.channelUsers.delete(channel);
  if (uiState.activeTab === channel) {
    updatePeopleList(channel);
  }
}

function addUserToChannel(channel, user) {
  if (!uiState.channelUsers.has(channel)) {
    uiState.channelUsers.set(channel, new Set());
  }
  uiState.channelUsers.get(channel).add(user);
  if (uiState.activeTab === channel) {
    updatePeopleList(channel);
  }
}

function removeUserFromChannel(channel, user) {
  const channelUsers = uiState.channelUsers.get(channel);
  if (channelUsers) {
    // Try with and without prefixes
    channelUsers.delete(user);
    channelUsers.delete('@' + user);
    channelUsers.delete('+' + user);
    if (user.startsWith('@') || user.startsWith('+')) {
      channelUsers.delete(user.substring(1));
    }
    if (uiState.activeTab === channel) {
      updatePeopleList(channel);
    }
  }
}

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

// Initialize the UI when the page loads
document.addEventListener('DOMContentLoaded', initUI);