import crypto from 'crypto';
import { readFileSync, writeFileSync, appendFileSync } from 'fs';
import { join } from 'path';
import axios from 'axios';

const TIMEOUT_SECONDS = 1800; // 30 Minuten

class Client {
  constructor(sessionId) {
    this.sessionId = sessionId;
    this.gender = '';
    this.country = '';
    this.isoCountryCode = '';
    this.userName = '';
    this.age = 0;
    this.conversations = {};
    this.lastActivity = new Date();
    this.loginTimeStamp = new Date();
    this.blockedUsers = new Set();
    this.socket = null; // Socket.IO Socket-Objekt
  }

  setActivity() {
    this.lastActivity = new Date();
  }

  activitiesTimedOut() {
    const secondsSinceActivity = (new Date() - this.lastActivity) / 1000;
    return secondsSinceActivity > TIMEOUT_SECONDS;
  }

  remainingSecondsToTimeout() {
    const secondsSinceActivity = (new Date() - this.lastActivity) / 1000;
    return Math.max(0, TIMEOUT_SECONDS - secondsSinceActivity);
  }

  currentlyLoggedInSeconds() {
    return Math.floor((new Date() - this.loginTimeStamp) / 1000);
  }

  toJSON() {
    return {
      sessionId: this.sessionId,
      userName: this.userName,
      gender: this.gender,
      country: this.country,
      isoCountryCode: this.isoCountryCode,
      age: this.age
    };
  }
}

let clients = new Map();
let conversations = new Map(); // Key: "user1:user2" (alphabetisch sortiert)

// Map: Socket-ID -> Express-Session-ID (für Session-Wiederherstellung)
let socketToSessionMap = new Map();

// Exportiere clients Map für Zugriff von außen
export function getClientsMap() {
  return clients;
}

// Exportiere Funktion zum Abrufen der Session-ID für einen Socket
export function getSessionIdForSocket(socketId) {
  return socketToSessionMap.get(socketId);
}

function extractSessionId(handshakeOrRequest) {
  // Unterstützt sowohl Socket.IO handshake als auch Express request
  const cookies = handshakeOrRequest.headers?.cookie || handshakeOrRequest.cookies || '';
  
  console.log('extractSessionId - Cookies:', cookies);
  
  const sessionMatch = cookies.match(/connect\.sid=([^;]+)/);
  if (sessionMatch) {
    let sessionId = sessionMatch[1];
    
    console.log('extractSessionId - Gefundenes Cookie:', sessionId);
    
    // Express-Session speichert die Session-ID als signierten Wert: s:xxxxx.signature
    // Die tatsächliche Session-ID ist nur xxxxx
    if (sessionId.startsWith('s:')) {
      const parts = sessionId.split('.');
      if (parts.length > 0) {
        sessionId = parts[0].substring(2); // Entferne 's:' Präfix
        console.log('extractSessionId - Bereinigte Session-ID:', sessionId);
      }
    }
    
    return sessionId;
  }
  
  console.log('extractSessionId - Kein connect.sid Cookie gefunden');
  // Fallback: Generiere temporäre UUID
  return crypto.randomUUID();
}

// Exportiere Funktion zum Prüfen des Session-Status
export function getSessionStatus(req) {
  // Verwende req.sessionID von Express-Session
  const sessionId = req.sessionID || extractSessionId(req);
  
  if (!sessionId) {
    return null;
  }
  
  const client = clients.get(sessionId);
  
  if (!client || !client.userName) {
    return null;
  }
  
  return {
    sessionId: client.sessionId,
    userName: client.userName,
    gender: client.gender,
    age: client.age,
    country: client.country,
    isoCountryCode: client.isoCountryCode
  };
}

function getConversationKey(user1, user2) {
  return [user1, user2].sort().join(':');
}

function logClientLogin(client) {
  try {
    const logPath = join(process.cwd(), 'logs', 'logins.log');
    const logEntry = `${new Date().toISOString()},${client.userName},${client.country},${client.age},${client.gender}\n`;
    appendFileSync(logPath, logEntry, 'utf-8');
  } catch (error) {
    console.error('Fehler beim Loggen des Logins:', error);
  }
}

function checkAndLogStart() {
  try {
    const logPath = join(process.cwd(), 'logs', 'starts.log');
    const logEntry = `${new Date().toISOString()}\n`;
    appendFileSync(logPath, logEntry, 'utf-8');
  } catch (error) {
    console.error('Fehler beim Loggen des Starts:', error);
  }
}

export function setupBroadcast(io) {
  // Länderliste beim Start laden
  let countriesMap = {};
  
  async function downloadCountries() {
    try {
      const response = await axios.get('https://pkgstore.datahub.io/core/country-list/data_csv/data/d7c9d7cfb42cb69f4422dec222dbbaa8/data_csv.csv');
      const lines = response.data.split('\n');
      countriesMap = {};
      
      // Parse CSV-Zeile mit Berücksichtigung von Anführungszeichen
      const parseCSVLine = (line) => {
        const result = [];
        let current = '';
        let inQuotes = false;
        
        for (let i = 0; i < line.length; i++) {
          const char = line[i];
          if (char === '"') {
            // Ignoriere Anführungszeichen, sie werden nicht zum Wert hinzugefügt
            inQuotes = !inQuotes;
          } else if (char === ',' && !inQuotes) {
            result.push(current.trim());
            current = '';
          } else {
            current += char;
          }
        }
        result.push(current.trim());
        return result;
      };
      
      for (let i = 1; i < lines.length; i++) {
        const line = lines[i].trim();
        if (!line) continue;
        
        const [name, code] = parseCSVLine(line);
        if (name && code) {
          // Entferne alle Anführungszeichen (auch am Anfang/Ende)
          const cleanName = name.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
          const cleanCode = code.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
          if (cleanName && cleanCode) {
            countriesMap[cleanName] = cleanCode.toLowerCase();
          }
        }
      }
      
      console.log(`Länderliste geladen: ${Object.keys(countriesMap).length} Länder`);
    } catch (error) {
      console.error('Fehler beim Laden der Länderliste:', error);
    }
  }
  
  downloadCountries();
  setInterval(downloadCountries, 24 * 60 * 60 * 1000); // Täglich aktualisieren

  // Socket.IO-Verbindungshandler
  io.on('connection', (socket) => {
    const request = socket.handshake;
    
    // Versuche Session-ID aus Cookie zu extrahieren
    let sessionId = extractSessionId(request);
    
    console.log('Socket.IO Connect - Session-ID (aus Cookie):', sessionId);
    console.log('Socket.IO Connect - Cookie:', request.headers?.cookie);
    
    // Wenn keine gültige Session-ID gefunden wurde, generiere eine temporäre UUID
    // Diese wird beim Login durch die Express-Session-ID ersetzt (siehe handleLogin)
    if (!sessionId || sessionId.length < 10 || !sessionId.match(/^[a-zA-Z0-9_-]+$/)) {
      sessionId = crypto.randomUUID();
      console.log('Socket.IO Connect - Keine gültige Session-ID gefunden, verwende temporäre UUID:', sessionId);
      socket.data.temporarySessionId = true; // Markiere als temporär
    }
    
    // Speichere Socket-ID mit Session-ID
    socket.data.sessionId = sessionId;
    
    let client = clients.get(sessionId);
    if (!client) {
      console.log('Socket.IO Connect - Neuer Client erstellt für Session-ID:', sessionId);
      client = new Client(sessionId);
      clients.set(sessionId, client);
    } else {
      console.log('Socket.IO Connect - Bestehender Client gefunden für Session-ID:', sessionId, 'User:', client.userName);
    }
    
    // Speichere Socket mit Session-ID
    client.socket = socket;
    
    // Bestätigung an Client senden, inklusive Benutzerdaten falls bereits eingeloggt
    const connectedData = { sessionId };
    if (client.userName) {
      connectedData.user = {
        userName: client.userName,
        gender: client.gender,
        age: client.age,
        country: client.country,
        isoCountryCode: client.isoCountryCode
      };
      connectedData.loggedIn = true;
    }
    socket.emit('connected', connectedData);

    socket.on('disconnect', (reason) => {
      const client = clients.get(sessionId);
      if (client) {
        // Setze Socket auf null, damit keine Nachrichten mehr an diesen Client gesendet werden
        // ABER: Lösche den Client NICHT, damit die Session beim Reload wiederhergestellt werden kann
        client.socket = null;
        
        // Aktualisiere Benutzerliste, damit andere Clients sehen, dass dieser Benutzer offline ist
        if (client.userName) {
          broadcastUserList();
        }
        // Client bleibt in der Map, damit Session-Wiederherstellung funktioniert
      }
    });

    socket.on('error', (error) => {
      console.error('Socket.IO-Fehler:', error);
    });

    // Socket.IO Event-Handler: Setze Express-Session-ID
    socket.on('setSessionId', (data) => {
      const { expressSessionId } = data;
      if (expressSessionId) {
        console.log('setSessionId - Express-Session-ID erhalten:', expressSessionId);
        const currentSessionId = socket.data.sessionId;
        
        if (currentSessionId !== expressSessionId) {
          console.log('setSessionId - Aktualisiere Session-ID von', currentSessionId, 'zu', expressSessionId);
          
          // Prüfe, ob bereits ein Client mit dieser Session-ID existiert
          let existingClient = clients.get(expressSessionId);
          
          // Wenn kein Client mit dieser Session-ID gefunden wurde, prüfe ob ein Client mit dem aktuellen Socket existiert
          // und bereits eingeloggt ist (für Session-Wiederherstellung nach Reload)
          if (!existingClient) {
            const currentClient = clients.get(currentSessionId);
            if (currentClient && currentClient.userName) {
              console.log('setSessionId - Client mit Session-ID', currentSessionId, 'ist bereits eingeloggt:', currentClient.userName);
              // Verwende bestehenden Client und aktualisiere nur die Session-ID
              existingClient = currentClient;
              clients.delete(currentSessionId);
              clients.set(expressSessionId, existingClient);
              existingClient.sessionId = expressSessionId;
            } else {
              // Wenn kein Client mit der aktuellen Session-ID gefunden wurde, suche nach einem Client,
              // der bereits eingeloggt ist und keinen aktiven Socket hat (für Session-Wiederherstellung)
              // Dies ist ein Fallback für den Fall, dass die Session-ID beim Reload geändert wurde
              for (const [sid, c] of clients.entries()) {
                if (c.userName && (!c.socket || !c.socket.connected)) {
                  console.log('setSessionId - Gefundener Client ohne aktiven Socket:', sid, c.userName);
                  // Verwende diesen Client und aktualisiere die Session-ID
                  existingClient = c;
                  clients.delete(sid);
                  clients.set(expressSessionId, existingClient);
                  existingClient.sessionId = expressSessionId;
                  break;
                }
              }
            }
          }
          
          if (existingClient) {
            // Verwende bestehenden Client
            console.log('setSessionId - Verwende bestehenden Client, User:', existingClient.userName || 'nicht eingeloggt');
            existingClient.socket = socket;
            socket.data.sessionId = expressSessionId;
            
            // Entferne alten Client, falls unterschiedlich
            if (currentSessionId !== expressSessionId && clients.has(currentSessionId)) {
              clients.delete(currentSessionId);
            }
            
            // Sende Login-Status zurück, falls bereits eingeloggt
            if (existingClient.userName) {
              console.log('setSessionId - Sende Login-Status zurück für User:', existingClient.userName);
              socket.emit('connected', {
                sessionId: expressSessionId,
                loggedIn: true,
                user: existingClient.toJSON()
              });
              
              // Aktualisiere Userliste für alle Clients, damit der wiederhergestellte Client die Liste erhält
              broadcastUserList();
            }
          } else {
            // Erstelle neuen Client mit Express-Session-ID
            console.log('setSessionId - Erstelle neuen Client');
            const newClient = new Client(expressSessionId);
            newClient.socket = socket;
            clients.set(expressSessionId, newClient);
            socket.data.sessionId = expressSessionId;
            
            // Entferne alten Client
            if (clients.has(currentSessionId)) {
              clients.delete(currentSessionId);
            }
          }
        }
      }
    });

    // Socket.IO Event-Handler
    // WICHTIG: Hole den Client immer dynamisch basierend auf socket.data.sessionId,
    // da sich die Session-ID nach setSessionId ändern kann
    socket.on('login', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        await handleLogin(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der Login-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('message', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleMessage(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der Message-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('requestConversation', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleRequestConversation(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der RequestConversation-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('userSearch', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleUserSearch(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der UserSearch-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('requestHistory', async () => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleRequestHistory(socket, currentClient);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der RequestHistory-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('requestOpenConversations', async () => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleRequestOpenConversations(socket, currentClient);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der RequestOpenConversations-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('blockUser', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleBlockUser(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der BlockUser-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

    socket.on('unblockUser', async (data) => {
      try {
        const currentClient = clients.get(socket.data.sessionId);
        if (!currentClient) {
          socket.emit('error', { message: 'Client nicht gefunden' });
          return;
        }
        currentClient.setActivity();
        handleUnblockUser(socket, currentClient, data);
      } catch (error) {
        console.error('Fehler beim Verarbeiten der UnblockUser-Nachricht:', error);
        socket.emit('error', { message: error.message });
      }
    });

  });

  async function handleLogin(socket, client, data) {
    const { userName, gender, age, country, expressSessionId } = data;
    
    // Validierung
    if (!userName || userName.trim().length < 3) {
      socket.emit('error', { message: 'Benutzername muss mindestens 3 Zeichen lang sein' });
      return;
    }
    
    // Wenn eine Express-Session-ID übergeben wurde, verwende diese statt der Socket-ID
    if (expressSessionId) {
      console.log('handleLogin - Express-Session-ID erhalten:', expressSessionId);
      
      // Entferne alten Client mit temporärer Socket-ID, falls vorhanden
      const oldSessionId = socket.data.sessionId;
      if (oldSessionId && oldSessionId !== expressSessionId && clients.has(oldSessionId)) {
        console.log('handleLogin - Entferne alten Client mit Session-ID:', oldSessionId);
        clients.delete(oldSessionId);
      }
      
      // Prüfe, ob bereits ein Client mit dieser Session-ID existiert
      let existingClient = clients.get(expressSessionId);
      if (existingClient) {
        // Verwende bestehenden Client
        console.log('handleLogin - Verwende bestehenden Client mit Session-ID:', expressSessionId);
        client = existingClient;
        // Aktualisiere Socket-Verbindung
        client.socket = socket;
        socket.data.sessionId = expressSessionId;
      } else {
        // Erstelle neuen Client mit Express-Session-ID
        console.log('handleLogin - Erstelle neuen Client mit Session-ID:', expressSessionId);
        client = new Client(expressSessionId);
        clients.set(expressSessionId, client);
        client.socket = socket;
        socket.data.sessionId = expressSessionId;
      }
    } else {
      console.log('handleLogin - Keine Express-Session-ID erhalten, verwende Socket-ID');
    }
    
    // Prüfe, ob Name bereits verwendet wird
    for (const [sid, c] of clients.entries()) {
      if (c.userName === userName && sid !== client.sessionId) {
        socket.emit('error', { message: 'Dieser Benutzername ist bereits vergeben' });
        return;
      }
    }
    
    client.userName = userName.trim();
    client.gender = gender;
    client.age = age;
    client.country = country;
    
    // ISO-Code aus Länderliste ermitteln
    client.isoCountryCode = countriesMap[country] || 'unknown';
    
    client.loginTimeStamp = new Date();
    client.setActivity();
    
    // Stelle sicher, dass der Socket gesetzt ist
    if (!client.socket) {
      console.log('handleLogin - WARNUNG: Socket nicht gesetzt, setze ihn jetzt');
      client.socket = socket;
    }
    
    console.log('handleLogin - Client nach Login:', {
      sessionId: client.sessionId,
      userName: client.userName,
      hasSocket: !!client.socket,
      socketConnected: client.socket ? client.socket.connected : false
    });
    
    logClientLogin(client);
    checkAndLogStart();
    
    // Benutzerliste an alle senden
    broadcastUserList();
    
    // Aktualisiere ungelesene Nachrichten für den neuen Benutzer
    updateUnreadCount(client);
    
    console.log('handleLogin - Sende loginSuccess an Socket');
    socket.emit('loginSuccess', { 
      sessionId: client.sessionId,
      user: client.toJSON()
    });
  }

  function handleMessage(socket, client, data) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const { toUserName, message, messageId, isImage, imageType } = data;
    
    if (!toUserName) {
      socket.emit('error', { message: 'Empfänger fehlt' });
      return;
    }
    
    // Finde Empfänger
    let receiver = null;
    for (const [sid, c] of clients.entries()) {
      if (c.userName === toUserName) {
        receiver = c;
        break;
      }
    }
    
    if (!receiver) {
      socket.emit('error', { message: 'Benutzer nicht gefunden' });
      return;
    }
    
    // Prüfe, ob Empfänger noch verbunden ist
    if (!receiver.socket || !receiver.socket.connected) {
      // Empfänger ist nicht mehr verbunden, entferne ihn aus der Liste
      clients.delete(receiver.sessionId);
      broadcastUserList();
      socket.emit('error', { message: 'Benutzer nicht gefunden' });
      return;
    }
    
    // Prüfe Blockierung
    if (receiver.blockedUsers.has(client.userName)) {
      socket.emit('error', { message: 'Du wurdest von diesem Benutzer blockiert' });
      return;
    }
    
    // Speichere Nachricht in Konversation
    const convKey = getConversationKey(client.userName, toUserName);
    if (!conversations.has(convKey)) {
      conversations.set(convKey, []);
    }
    
    const conversation = conversations.get(convKey);
    conversation.push({
      from: client.userName,
      to: toUserName,
      message,
      messageId,
      timestamp: new Date().toISOString(),
      read: false,
      isImage: isImage || false,
      imageType: imageType || null
    });
    
    // Sende an Empfänger (wenn online)
    const messagePayload = {
      from: client.userName,
      message,
      messageId,
      timestamp: new Date().toISOString(),
      isImage: isImage || false,
      imageType: imageType || null
    };
    
    // Debug-Logging für Bilder
    if (isImage) {
      console.log(`[Bild] Sende Bild von ${client.userName} an ${toUserName}, Größe: ${message ? message.length : 0} Zeichen, Typ: ${imageType || 'unbekannt'}`);
    }
    
    receiver.socket.emit('message', messagePayload);
    
    // Bestätigung an Absender
    socket.emit('messageSent', { 
      messageId,
      to: toUserName
    });
    
    // Aktualisiere ungelesene Nachrichten für den Empfänger
    updateUnreadCount(receiver);
  }

  function handleRequestConversation(socket, client, data) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const { withUserName } = data;
    const convKey = getConversationKey(client.userName, withUserName);
    const conversation = conversations.get(convKey) || [];
    
    // Markiere alle Nachrichten von diesem Benutzer als gelesen
    for (const msg of conversation) {
      if (msg.to === client.userName && msg.from === withUserName) {
        msg.read = true;
      }
    }
    
    // Aktualisiere ungelesene Nachrichten nach dem Markieren als gelesen
    updateUnreadCount(client);
    
    socket.emit('conversation', {
      with: withUserName,
      messages: conversation.map(msg => ({
        from: msg.from,
        message: msg.message,
        timestamp: msg.timestamp,
        isImage: msg.isImage || false,
        imageType: msg.imageType || null
      }))
    });
  }

  function handleUserSearch(socket, client, data) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const { nameIncludes, minAge, maxAge, countries, genders } = data;
    
    const results = [];
    for (const [sid, c] of clients.entries()) {
      if (!c.userName || c.userName === client.userName) continue;
      
      // Name-Filter
      if (nameIncludes && !c.userName.toLowerCase().includes(nameIncludes.toLowerCase())) {
        continue;
      }
      
      // Alter-Filter
      if (minAge && c.age < minAge) continue;
      if (maxAge && c.age > maxAge) continue;
      
      // Länder-Filter
      if (countries && countries.length > 0 && !countries.includes(c.country)) {
        continue;
      }
      
      // Geschlecht-Filter
      if (genders && genders.length > 0 && !genders.includes(c.gender)) {
        continue;
      }
      
      results.push(c.toJSON());
    }
    
    socket.emit('searchResults', {
      results
    });
  }

  function handleRequestHistory(socket, client) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const history = [];
    for (const [convKey, messages] of conversations.entries()) {
      const [user1, user2] = convKey.split(':');
      if (user1 === client.userName || user2 === client.userName) {
        const otherUser = user1 === client.userName ? user2 : user1;
        history.push({
          userName: otherUser,
          lastMessage: messages.length > 0 ? messages[messages.length - 1] : null
        });
      }
    }
    
    socket.emit('historyResults', {
      results: history
    });
  }

  function handleRequestOpenConversations(socket, client) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const inbox = [];
    for (const [convKey, messages] of conversations.entries()) {
      const [user1, user2] = convKey.split(':');
      if (user1 === client.userName || user2 === client.userName) {
        const otherUser = user1 === client.userName ? user2 : user1;
        const unreadCount = messages.filter(m => 
          m.to === client.userName && !m.read
        ).length;
        
        if (unreadCount > 0) {
          inbox.push({
            userName: otherUser,
            unreadCount
          });
        }
      }
    }
    
    socket.emit('inboxResults', {
      results: inbox
    });
  }

  function handleBlockUser(socket, client, data) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const { userName } = data;
    client.blockedUsers.add(userName);
    
    socket.emit('userBlocked', {
      userName
    });
  }

  function handleUnblockUser(socket, client, data) {
    if (!client.userName) {
      socket.emit('error', { message: 'Nicht eingeloggt' });
      return;
    }
    
    const { userName } = data;
    client.blockedUsers.delete(userName);
    
    socket.emit('userUnblocked', {
      userName
    });
  }

  function updateUnreadCount(client) {
    if (!client.userName || !client.socket || !client.socket.connected) {
      return;
    }
    
    // Zähle Personen mit ungelesenen Nachrichten für diesen Benutzer
    let unreadPersons = 0;
    for (const [convKey, messages] of conversations.entries()) {
      const [user1, user2] = convKey.split(':');
      if (user1 === client.userName || user2 === client.userName) {
        const unreadCount = messages.filter(m => 
          m.to === client.userName && !m.read
        ).length;
        if (unreadCount > 0) {
          unreadPersons++;
        }
      }
    }
    
    // Sende Update an Client
    client.socket.emit('unreadChats', {
      count: unreadPersons
    });
  }

  function broadcastUserList() {
    // Filtere nur eingeloggte Benutzer mit aktiver Verbindung
    const userList = Array.from(clients.values())
      .filter(c => {
        const hasUserName = !!c.userName;
        const hasSocket = !!c.socket;
        const isConnected = c.socket && c.socket.connected;
        if (hasUserName && (!hasSocket || !isConnected)) {
          console.log('broadcastUserList - Client ohne Socket oder nicht verbunden:', c.userName, 'socket:', hasSocket, 'connected:', isConnected);
        }
        return hasUserName && hasSocket && isConnected;
      })
      .map(c => c.toJSON());
    
    console.log('broadcastUserList - Sende Userliste mit', userList.length, 'Benutzern:', userList.map(u => u.userName));
    
    // Sende an alle verbundenen Clients
    io.emit('userList', {
      users: userList
    });
  }

  function broadcastToUser(userName, data) {
    // Finde den Client mit diesem Benutzernamen und sende die Nachricht
    for (const [sid, c] of clients.entries()) {
      if (c.userName === userName && c.socket) {
        c.socket.emit(data.type, data);
        return;
      }
    }
  }

  // Timeout-Check alle 60 Sekunden
  setInterval(() => {
    for (const [sid, client] of clients.entries()) {
      if (client.activitiesTimedOut()) {
        console.log(`Client ${client.userName} hat Timeout erreicht`);
        clients.delete(sid);
        broadcastUserList();
      }
    }
  }, 60000);
}

