<script lang="ts">
  import { onMount, onDestroy, createEventDispatcher } from 'svelte';
  import { MudConnection } from '$lib/connection/MudConnection';
  import { ConnectionManager, activeConnections } from '$lib/connection/ConnectionManager';
  import { GmcpHandler } from '$lib/gmcp/GmcpHandler';
  import { TriggerSystem } from '$lib/triggers/TriggerSystem';
  import { AccessibilityManager } from '$lib/accessibility/AccessibilityManager';
  import { 
    connections, 
    connectionStatus, 
    activeProfileId, 
    activeProfile,
    profiles, 
    addToOutputHistory, 
    updateGmcpData,
    accessibilitySettings,
    uiSettings,
    outputHistory
  } from '$lib/stores/mudStore';
  import { get } from 'svelte/store';
  
  const dispatch = createEventDispatcher();
  
  // Props
  export let profileId: string;
  export let autoConnect = false;
  
  // Local state
  let connection: MudConnection | null = null;
  let connectionManager: ConnectionManager | null = null;
  let gmcpHandler: GmcpHandler | null = null;
  let triggerSystem: TriggerSystem | null = null;
  let accessibilityManager: AccessibilityManager | null = null;
  
  /**
   * Handle keyboard events for speech control
   */
  function handleKeyDown(event: KeyboardEvent): void {
    // Control key stops speech - the key code for Control is 17
    if (event.key === 'Control' || event.ctrlKey || event.keyCode === 17) {
      // Stop propagation to ensure no other handlers interfere
      event.stopPropagation();
      
      if (accessibilityManager && accessibilityManager.isSpeaking()) {
        console.log('Control key pressed - stopping speech');
        accessibilityManager.stopSpeech();
      }
    }
    
    // Enter key stops speech if the setting is enabled
    if ((event.key === 'Enter' || event.keyCode === 13) && $accessibilitySettings.interruptSpeechOnEnter) {
      if (accessibilityManager && accessibilityManager.isSpeaking()) {
        console.log('Enter key pressed - interrupting speech');
        accessibilityManager.stopSpeech();
      }
    }
  }
  
  let unsubscribeFunctions = [];
  
  onMount(() => {
    console.log(`MudConnection component mounted for profile: ${profileId}`);
    
    // Initialize components
    initializeComponents();
    
    // Set up keyboard listener for speech control - use capture phase and make it top-level
    document.addEventListener('keydown', handleKeyDown, true); // Using document instead of window
    
    // Get the connection status from the store
    const currentStatus = get(connectionStatus)[profileId];
    
    // Check if we already have a connection in the ConnectionManager
    if (currentStatus === 'connected' || currentStatus === 'connecting') {
      console.log(`Connection exists for ${profileId}, getting from manager`);
      const connectionManager = ConnectionManager.getInstance();
      const existingConnection = connectionManager.getExistingConnection(profileId);
      
      if (existingConnection) {
        console.log(`Found existing connection for ${profileId}, updating local ref`);
        // Update the connections store
        connections.update(conns => ({
          ...conns,
          [profileId]: existingConnection
        }));
        
        // Update local reference
        connection = existingConnection;
        // Re-attach listeners
        setupConnectionListeners(existingConnection);
      }
    } else {
      // Register this connection in the connections store with component instance
      connections.update(conns => {
        console.log(`Registering connection component for profile: ${profileId}`);
        return {
          ...conns,
          [profileId]: this
        };
      });
      
      // Update connection status - ensure UI shows status as 'disconnected' at start
      if (!currentStatus) {
        connectionStatus.update(statuses => {
          console.log(`Setting connection status for ${profileId} to 'disconnected'`);
          return {
            ...statuses,
            [profileId]: 'disconnected'
          };
        });
      }
    }
    
    // Dump the current connection status for debugging
    setTimeout(() => {
      console.log('Current connection status at initialization:', get(connectionStatus));
    }, 100);
    
    // Auto-connect if enabled and not already connected - with a slight delay
    if (autoConnect && currentStatus !== 'connected') {
      console.log('Auto-connecting profile:', profileId);
      setTimeout(() => connect(), 100);
    }
  });
  
  onDestroy(() => {
    console.log(`MudConnection component being destroyed for profile: ${profileId}`);
    // Remove keyboard listener
    document.removeEventListener('keydown', handleKeyDown, true); // Match document and capture phase
    
    // Don't disconnect the connection - it should persist even when the component is unmounted
    // Only remove this component instance from the local connections store (not the ConnectionManager)
    connections.update(conns => {
      const newConns = { ...conns };
      delete newConns[profileId];
      return newConns;
    });
    
    // Clean up subscriptions
    unsubscribeFunctions.forEach(unsubFn => {
      if (typeof unsubFn === 'function') {
        try {
          unsubFn();
        } catch (error) {
          console.error('Error during unsubscribe:', error);
        }
      }
    });
  });
  
  /**
   * Initialize connection components
   */
  function initializeComponents() {
    // Get singleton instance of ConnectionManager
    connectionManager = ConnectionManager.getInstance();
    
    // Create GMCP handler
    gmcpHandler = new GmcpHandler();
    
    // Create trigger system
    triggerSystem = new TriggerSystem();
    
    // Create accessibility manager
    accessibilityManager = new AccessibilityManager();
    
    // Set up event listeners
    setupEventListeners();
    
    // Get or create connection from ConnectionManager
    updateConnectionFromStore();
  }
  
  /**
   * Update local connection reference from store
   */
  function updateConnectionFromStore() {
    // Subscribe to activeConnections to get updates
    const unsubscribe = activeConnections.subscribe(connections => {
      connection = connections[profileId] || null;
      
      if (connection) {
        // Re-attach event listeners when connection changes
        setupConnectionListeners(connection);
      }
    });
    
    // Add to unsubscribe functions
    unsubscribeFunctions.push(unsubscribe);
  }
  
  /**
   * Set up listeners for a specific connection
   */
  function setupConnectionListeners(conn: MudConnection) {
    // First remove ALL event listeners to prevent duplicates
    console.log('Setting up connection listeners and removing old ones');
    conn.off('received');
    conn.off('sent');
    conn.off('connected');
    conn.off('disconnected');
    conn.off('error');
    
    // Add new listeners
    conn.on('received', handleReceived);
    conn.on('sent', handleSent);
    conn.on('connected', handleConnected);
    conn.on('disconnected', handleDisconnected);
    conn.on('error', handleError);
  }
  
  /**
   * Set up event listeners for components
   */
  function setupEventListeners() {
    if (!gmcpHandler || !triggerSystem || !accessibilityManager) return;
    
    // GMCP handler events
    gmcpHandler.on('gmcp', (module, data) => {
      updateGmcpData(module, data);
    });
    
    gmcpHandler.on('sendGmcp', (module, data) => {
      if (connection) {
        connection.sendGmcp(module, data);
      }
    });
    
    gmcpHandler.on('playSound', (url, volume, loop) => {
      dispatch('playSound', { url, volume, loop });
    });
    
    // Trigger system events
    triggerSystem.on('sendText', (text) => {
      if (connection) {
        connection.send(text);
      }
    });
    
    triggerSystem.on('highlight', (text, pattern, color, isRegex) => {
      dispatch('highlight', { text, pattern, color, isRegex });
    });
    
    // Set up TTS subscription - use direct subscription to avoid circular updates
    const unsubscribeTts = accessibilitySettings.subscribe(settings => {
      try {
        // Set speech enabled directly based on the store value
        if (accessibilityManager) {
          console.log('Setting TTS from store:', settings.textToSpeech);
          accessibilityManager.setSpeechEnabled(settings.textToSpeech);
          
          // Update speech options when settings change
          accessibilityManager.updateSpeechOptions({
            rate: settings.speechRate,
            pitch: settings.speechPitch,
            volume: settings.speechVolume
          });
        }
      } catch (error) {
        console.error('Error updating TTS setting:', error);
      }
    });
    unsubscribeFunctions.push(unsubscribeTts);
    
    // Set up only GMCP debugging subscription
    let previousGmcpDebug = $uiSettings.debugGmcp;
    const unsubscribeUiSettings = uiSettings.subscribe(settings => {
      if (settings.debugGmcp !== previousGmcpDebug) {
        previousGmcpDebug = settings.debugGmcp;
      }
    });
    unsubscribeFunctions.push(unsubscribeUiSettings);
  }
  
  /**
   * Connect to the MUD server
   */
  export function connect() {
    try {
      // First check if we are already connected
      const currentStatus = get(connectionStatus)[profileId];
      if (currentStatus === 'connected' || currentStatus === 'connecting') {
        console.log(`Already ${currentStatus} for profile ${profileId}, not connecting again`);
        return;
      }
      
      // Find the profile by ID - don't rely on activeProfile
      const allProfiles = get(profiles);
      const profile = allProfiles.find(p => p.id === profileId);
      
      console.log(`Connecting to profile ${profileId}:`, profile);
      
      if (!profile) {
        addToOutputHistory(`Error: Profile ${profileId} not found.`);
        console.error(`Profile ${profileId} not found`);
        return;
      }
      
      // Update connection status
      connectionStatus.update(statuses => {
        console.log(`Setting connection status for ${profileId} to 'connecting'`);
        return {
          ...statuses,
          [profileId]: 'connecting'
        };
      });
      
      // Only add to output history if this is the active profile
      if (get(activeProfileId) === profileId) {
        addToOutputHistory(`Connecting to ${profile.host}:${profile.port}...`);
      }
      
      // Use the connection manager to get or create a connection
      if (!connectionManager) {
        connectionManager = ConnectionManager.getInstance();
      }
      
      // Connect using the connection manager
      connectionManager.connect(profileId, {
        host: profile.host,
        port: profile.port,
        useSSL: profile.useSSL,
        gmcpHandler: gmcpHandler || undefined
      });
      
      // Update local connection reference
      setTimeout(() => {
        updateConnectionFromStore();
      }, 100);
      
    } catch (error) {
      console.error(`Failed to connect to ${profileId}:`, error);
      
      connectionStatus.update(statuses => {
        return {
          ...statuses,
          [profileId]: 'error'
        };
      });
      
      const errorMsg = `Error connecting to profile ${profileId}: ${error}`;
      console.error(errorMsg);
      
      // Only add to output history if this is the active profile
      if (get(activeProfileId) === profileId) {
        addToOutputHistory(errorMsg);
      }
    }
  }
  
  /**
   * Disconnect from the MUD server
   */
  export function disconnect() {
    if (!connectionManager) {
      connectionManager = ConnectionManager.getInstance();
    }
    
    connectionManager.disconnect(profileId);
    console.log(`Disconnected profile ${profileId}`);
  }
  
  /**
   * Handle connection established
   */
  function handleConnected() {
    try {
      // Find the profile by ID
      const allProfiles = get(profiles);
      const profile = allProfiles.find(p => p.id === profileId);
      
      console.log(`Profile ${profileId} connected:`, profile);
      
      // Update connection status GLOBALLY, not just for this profile
      connectionStatus.update(statuses => {
        console.log(`Setting connection status for ${profileId} to 'connected'`);
        console.log('Previous connection statuses:', statuses);
        const newStatuses = {
          ...statuses,
          [profileId]: 'connected'
        };
        console.log('New connection statuses:', newStatuses);
        return newStatuses;
      });
      
      // Dump the current connection status for debugging
      setTimeout(() => {
        console.log('Current connection status after connect:', get(connectionStatus));
      }, 100);
      
      // Only add to output history if this is the active profile
      if (get(activeProfileId) === profileId) {
        addToOutputHistory(`Connected to ${profile?.host}:${profile?.port}`);
      }
    
    // Handle auto-login if enabled
    if (profile?.autoLogin?.enabled) {
      setTimeout(() => {
        // Send username
        if (profile.autoLogin?.username) {
          if (connection) connection.send(profile.autoLogin.username);
        }
        
        // Send password after a delay
        if (profile.autoLogin?.password) {
          setTimeout(() => {
            if (connection) connection.send(profile.autoLogin?.password || '');
            
            // Send additional commands
            if (profile.autoLogin?.commands && profile.autoLogin.commands.length > 0) {
              let delay = 500;
              profile.autoLogin.commands.forEach((cmd) => {
                setTimeout(() => {
                  if (connection) connection.send(cmd);
                }, delay);
                delay += 500;
              });
            }
          }, 1000);
        }
      }, 1000);
    }
    
    dispatch('connected');
    } catch (error) {
      console.error(`Error handling connection for profile ${profileId}:`, error);
    }
  }
  
  /**
   * Handle connection closed
   */
  function handleDisconnected() {
    console.log(`Profile ${profileId} disconnected`);
    
    connectionStatus.update(statuses => {
      console.log(`Setting connection status for ${profileId} to 'disconnected'`);
      return {
        ...statuses,
        [profileId]: 'disconnected'
      };
    });
    
    // Only add to output history if this is the active profile
    if (get(activeProfileId) === profileId) {
      addToOutputHistory('Disconnected from server.');
    }
    
    dispatch('disconnected');
  }
  
  /**
   * Handle connection error
   */
  function handleError(error: any) {
    console.log(`Profile ${profileId} connection error:`, error);
    
    connectionStatus.update(statuses => {
      console.log(`Setting connection status for ${profileId} to 'error'`);
      return {
        ...statuses,
        [profileId]: 'error'
      };
    });
    
    // Format the error message for display
    const errorMessage = typeof error === 'object' ? 
      (error.message || JSON.stringify(error)) : 
      String(error);
    
    // Only add to output history if this is the active profile
    if (get(activeProfileId) === profileId) {
      addToOutputHistory(`Connection error: ${errorMessage}`, false, [
        { pattern: 'Connection error', color: '#ff5555', isRegex: false }
      ]);
    }
    
    dispatch('error', { error });
  }
  
  /**
   * Handle received data
   */
  function handleReceived(text: string) {
    console.log(`Profile ${profileId} received data, active profile: ${get(activeProfileId)}`);
    
    try {
      // First check if this is the active profile - only handle messages for the active profile
      if (get(activeProfileId) !== profileId) {
        console.log(`Ignoring received data for inactive profile ${profileId}`);
        return;
      }
      
      // First, ensure this profile has an output history entry
      const history = get(outputHistory);
      if (!history[profileId] || !Array.isArray(history[profileId])) {
        console.log(`Creating fresh output history for profile ${profileId}`);
        outputHistory.update(h => ({
          ...h,
          [profileId]: []
        }));
      }
      
      // Create the output item
      const outputItem = {
        id: `output-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
        text,
        timestamp: Date.now(),
        isInput: false,
        highlights: []
      };
      
      // Add directly to this profile's history
      outputHistory.update(history => {
        console.log(`Adding text to history for profile ${profileId}`);
        const profileHistory = history[profileId] || [];
        return {
          ...history,
          [profileId]: [...profileHistory, outputItem]
        };
      });
      
      // Process triggers with safe error handling
      if (triggerSystem) {
        try {
          triggerSystem.processTriggers(text);
        } catch (error) {
          console.error(`Error processing triggers for ${profileId}:`, error);
        }
      }
    
      // Try to use text-to-speech if enabled
      if (accessibilityManager && $accessibilitySettings.textToSpeech && get(activeProfileId) === profileId) {
        // Use a small timeout to avoid UI blocking
        setTimeout(() => {
          try {
            accessibilityManager.speak(text);
          } catch (error) {
            console.error('Error using text-to-speech:', error);
          }
        }, 10);
      }
      
      dispatch('received', { text });
    } catch (error) {
      console.error(`Error handling received data for profile ${profileId}:`, error);
    }
  }
  
  /**
   * Handle sent data
   */
  function handleSent(text: string) {
    dispatch('sent', { text });
  }
</script>

{#if $connectionStatus[profileId]}
  <div class="mud-connection-status" role="status" aria-live="polite">
    <div class="status-indicator status-{$connectionStatus[profileId]}" aria-hidden="true"></div>
    <span>Server status: {$connectionStatus[profileId]}</span>
    {#if $connectionStatus[profileId] === 'error'}
      <span class="sr-only">There was an error connecting to the MUD server. Please check your settings and try again.</span>
    {/if}
  </div>
{/if}

<style>
  .mud-connection-status {
    display: flex;
    align-items: center;
    padding: 5px;
    font-size: 0.9em;
  }
  
  .status-indicator {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 5px;
  }
  
  .status-connected {
    background-color: #50fa7b;
  }
  
  .status-connecting {
    background-color: #f1fa8c;
  }
  
  .status-disconnected {
    background-color: #999;
  }
  
  .status-error {
    background-color: #ff5555;
  }
  
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
  }
</style>
