import { Server } from 'socket.io';

let io = null;

export const initializeSocketIO = (httpServer) => {
  // Verhindere doppelte Initialisierung
  if (io) {
    console.warn('⚠️  Socket.IO wurde bereits initialisiert. Überspringe erneute Initialisierung.');
    return io;
  }

  io = new Server(httpServer, {
    cors: {
      origin: (origin, callback) => {
        // Erlaube alle Origins für Socket.IO (da wir direkten HTTPS-Zugang haben)
        callback(null, true);
      },
      credentials: true,
      methods: ['GET', 'POST'],
      allowedHeaders: ['Content-Type', 'Authorization', 'authcode', 'userid']
    },
    // Wichtig für Reverse Proxy (Apache/Nginx): Path und Transports explizit setzen
    path: '/socket.io/',
    transports: ['polling', 'websocket'], // Polling zuerst für bessere Kompatibilität
    // Erlaube Upgrade von polling zu websocket
    allowUpgrades: true,
    // Timeout für Upgrade - erhöht für bessere Kompatibilität
    upgradeTimeout: 30000,
    // Ping-Timeout für Verbindungen
    pingTimeout: 60000,
    pingInterval: 25000,
    // Wichtig für Reverse Proxy: Erlaube WebSocket-Upgrades auch ohne Origin-Header
    allowEIO3: true,
    // Erlaube WebSocket-Upgrades auch wenn der Request von einem Proxy kommt
    serveClient: false,
    // Verbesserte Cookie-Handling für Cross-Origin
    cookie: {
      name: 'io',
      httpOnly: false,
      sameSite: 'lax',
      path: '/'
    },
    // Erlaube Cross-Origin-Verbindungen
    connectTimeout: 45000,
    // Erlaube WebSocket-Upgrades auch bei Cross-Origin
    perMessageDeflate: false, // Deaktiviert für bessere Kompatibilität
    maxHttpBufferSize: 1e6 // 1MB
  });
  
  // Verbesserte WebSocket-Upgrade-Logging
  io.engine.on('upgrade', (req, socket, head) => {
    console.log(`🔄 Socket.IO Upgrade-Versuch: ${req.url}`);
    console.log(`   Upgrade-Header: ${req.headers.upgrade}`);
    console.log(`   Connection-Header: ${req.headers.connection}`);
    console.log(`   Sec-WebSocket-Key: ${req.headers['sec-websocket-key']?.substring(0, 20)}...`);
  });
  
  io.engine.on('upgradeError', (err, req, socket, head) => {
    console.error('❌ Socket.IO Upgrade Error:', err.message || err);
    if (req) {
      console.error('   URL:', req.url);
      console.error('   Upgrade-Header:', req.headers.upgrade);
      console.error('   Connection-Header:', req.headers.connection);
      console.error('   Method:', req.method);
    }
    if (err.stack) {
      console.error('   Stack:', err.stack);
    }
  });

  // Error-Handling für Socket.IO
  io.engine.on('connection_error', (err) => {
    // "Session ID unknown" ist normal nach Server-Neustarts - weniger alarmierend loggen
    if (err.message && err.message.includes('Session ID unknown')) {
      console.warn('⚠️  Socket.IO: Unbekannte Session-ID (normal nach Server-Neustart)');
      if (err.context && err.context.sid) {
        console.warn(`   Session-ID: ${err.context.sid}`);
      }
      // Client wird automatisch reconnecten - kein weiteres Action nötig
      return;
    }
    
    // Andere Fehler normal loggen
    console.error('❌ Socket.IO Connection Error:', err.message || err);
    if (err.req) {
      console.error('   Request:', err.req.url);
      console.error('   Method:', err.req.method);
    }
    console.error('   Code:', err.code);
    console.error('   Type:', err.type);
    console.error('   Context:', err.context);
    if (err.stack) {
      console.error('   Stack:', err.stack);
    }
  });
  
  // Detailliertes Request-Logging für Debugging
  io.engine.on('initial_headers', (headers, req) => {
    // Logge nur bei Problemen
    if (process.env.DEBUG_SOCKETIO === 'true') {
      console.log('📡 Socket.IO Request:', req.method, req.url);
    }
  });

  io.on('connection', (socket) => {
    console.log(`✅ Socket.IO Client verbunden: ${socket.id}`);
    console.log(`   Transport: ${socket.conn.transport.name}`);
    console.log(`   Origin: ${socket.handshake.headers.origin || 'unknown'}`);

    // Logge Transport-Upgrades
    socket.conn.on('upgrade', () => {
      console.log(`🔄 Socket.IO Transport Upgrade für ${socket.id}: ${socket.conn.transport.name}`);
    });

    socket.conn.on('upgradeError', (error) => {
      console.error(`❌ Socket.IO Transport Upgrade Error für ${socket.id}:`, error.message);
    });

    // Client tritt einem Club-Raum bei
    socket.on('join-club', (clubId) => {
      const room = `club-${clubId}`;
      socket.join(room);
      console.log(`   Client ${socket.id} tritt Raum bei: ${room}`);
    });

    // Client verlässt einen Club-Raum
    socket.on('leave-club', (clubId) => {
      const room = `club-${clubId}`;
      socket.leave(room);
      console.log(`   Client ${socket.id} verlässt Raum: ${room}`);
    });

    socket.on('disconnect', (reason) => {
      console.log(`❌ Socket.IO Client getrennt: ${socket.id}, Grund: ${reason}`);
    });

    socket.on('error', (error) => {
      console.error(`❌ Socket.IO Client Error für ${socket.id}:`, error);
    });
  });

  console.log('✅ Socket.IO erfolgreich initialisiert');
  return io;
};

export const getIO = () => {
  if (!io) {
    throw new Error('Socket.IO wurde noch nicht initialisiert. Rufe zuerst initializeSocketIO() auf.');
  }
  return io;
};

// Helper-Funktionen zum Emittieren von Events
export const emitToClub = (clubId, event, data) => {
  if (!io) {
    console.warn('emitToClub: io nicht initialisiert');
    return;
  }
  const room = `club-${clubId}`;
  io.to(room).emit(event, data);
};

// Events für Diary-Änderungen
export const emitParticipantAdded = (clubId, dateId, participant) => {
  emitToClub(clubId, 'participant:added', { dateId, participant });
};

export const emitParticipantRemoved = (clubId, dateId, participantId) => {
  emitToClub(clubId, 'participant:removed', { dateId, participantId });
};

export const emitParticipantUpdated = (clubId, dateId, participant) => {
  emitToClub(clubId, 'participant:updated', { dateId, participant });
};

export const emitDiaryNoteAdded = (clubId, dateId, note) => {
  emitToClub(clubId, 'diary:note:added', { dateId, note });
};

export const emitDiaryNoteUpdated = (clubId, dateId, note) => {
  emitToClub(clubId, 'diary:note:updated', { dateId, note });
};

export const emitDiaryNoteDeleted = (clubId, dateId, noteId) => {
  emitToClub(clubId, 'diary:note:deleted', { dateId, noteId });
};

export const emitDiaryTagAdded = (clubId, dateId, tag) => {
  emitToClub(clubId, 'diary:tag:added', { dateId, tag });
};

export const emitDiaryTagRemoved = (clubId, dateId, tagId) => {
  emitToClub(clubId, 'diary:tag:removed', { dateId, tagId });
};

export const emitDiaryDateUpdated = (clubId, dateId, updates) => {
  emitToClub(clubId, 'diary:date:updated', { dateId, updates });
};

export const emitActivityMemberAdded = (clubId, activityId, participantId, dateId) => {
  emitToClub(clubId, 'activity:member:added', { activityId, participantId, dateId });
};

export const emitActivityMemberRemoved = (clubId, activityId, participantId, dateId) => {
  emitToClub(clubId, 'activity:member:removed', { activityId, participantId, dateId });
};

// Event für Aktivitäts-Änderungen (erstellen, aktualisieren, löschen, Reihenfolge ändern)
export const emitActivityChanged = (clubId, dateId) => {
  emitToClub(clubId, 'activity:changed', { dateId });
};

// Event für Member-Änderungen (erstellen, aktualisieren)
export const emitMemberChanged = (clubId) => {
  emitToClub(clubId, 'member:changed', { clubId });
};

// Event für Gruppen-Änderungen (erstellen, aktualisieren, löschen)
export const emitGroupChanged = (clubId, dateId) => {
  emitToClub(clubId, 'group:changed', { dateId });
};

// Event für Tournament-Änderungen (alle Aktionen)
export const emitTournamentChanged = (clubId, tournamentId) => {
  emitToClub(clubId, 'tournament:changed', { tournamentId });
};

// Event wenn Spielerauswahl (Bereit/Geplant/Gespielt) für ein Match geändert wurde (match = vollständiges angereichertes Match-Objekt)
export const emitScheduleMatchUpdated = (clubId, matchId, match = null) => {
  emitToClub(clubId, 'schedule:match:updated', { clubId, matchId, match });
};

export const emitFriendlyInvitationCreated = (fromClubId, toClubId, invitation) => {
  emitToClub(fromClubId, 'friendly:invitation:created', { invitation });
  if (String(fromClubId) !== String(toClubId)) {
    emitToClub(toClubId, 'friendly:invitation:created', { invitation });
  }
};

export const emitFriendlyInvitationAccepted = (fromClubId, toClubId, invitation) => {
  emitToClub(fromClubId, 'friendly:invitation:accepted', { invitation });
  if (String(fromClubId) !== String(toClubId)) {
    emitToClub(toClubId, 'friendly:invitation:accepted', { invitation });
  }
};

export const emitFriendlyInvitationDeclined = (fromClubId, toClubId, invitationId) => {
  const payload = { invitationId };
  emitToClub(fromClubId, 'friendly:invitation:declined', payload);
  if (String(fromClubId) !== String(toClubId)) {
    emitToClub(toClubId, 'friendly:invitation:declined', payload);
  }
};

export const emitFriendlySharedMatchUpdated = (homeClubId, guestClubId, match) => {
  emitToClub(homeClubId, 'friendly:shared:match:updated', { match });
  if (String(homeClubId) !== String(guestClubId)) {
    emitToClub(guestClubId, 'friendly:shared:match:updated', { match });
  }
};

export const emitFriendlySharedMatchDeleted = (homeClubId, guestClubId, matchId) => {
  const payload = { matchId };
  emitToClub(homeClubId, 'friendly:shared:match:deleted', payload);
  if (String(homeClubId) !== String(guestClubId)) {
    emitToClub(guestClubId, 'friendly:shared:match:deleted', payload);
  }
};

// Event wenn Spielbericht (nuscore) abgesendet wurde – matchData = vollständiges Objekt für andere Clients
export const emitMatchReportSubmitted = (clubId, matchCode, matchData = null) => {
  emitToClub(clubId, 'schedule:match-report:submitted', { clubId, matchCode, matchData });
};

