const { v4: uuidv4 } = require('uuid');

class SessionManager {
  constructor() {
    this.sessions = new Map(); // sessionId -> SessionInfo
    this.deviceSessions = new Map(); // deviceId -> Set(sessionIds)
    this.operatorSessions = new Map(); // operatorId -> Set(sessionIds)
  }

  /**
   * Создание новой сессии
   * @param {string} deviceId 
   * @param {string} operatorId 
   * @param {string} cameraType 
   * @returns {SessionInfo}
   */
  createSession(deviceId, operatorId, cameraType = 'back') {
    const sessionId = uuidv4();
    const session = new SessionInfo(sessionId, deviceId, operatorId, cameraType);
    
    this.sessions.set(sessionId, session);
    
    // Добавляем к устройству
    if (!this.deviceSessions.has(deviceId)) {
      this.deviceSessions.set(deviceId, new Set());
    }
    this.deviceSessions.get(deviceId).add(sessionId);
    
    // Добавляем к оператору
    if (!this.operatorSessions.has(operatorId)) {
      this.operatorSessions.set(operatorId, new Set());
    }
    this.operatorSessions.get(operatorId).add(sessionId);
    
    return session;
  }

  /**
   * Получение сессии по ID
   * @param {string} sessionId 
   * @returns {SessionInfo|null}
   */
  getSession(sessionId) {
    return this.sessions.get(sessionId) || null;
  }

  /**
   * Получение всех сессий устройства
   * @param {string} deviceId 
   * @returns {SessionInfo[]}
   */
  getDeviceSessions(deviceId) {
    const sessionIds = this.deviceSessions.get(deviceId);
    if (!sessionIds) return [];
    
    return Array.from(sessionIds)
      .map(id => this.sessions.get(id))
      .filter(session => session !== undefined);
  }

  /**
   * Получение всех сессий оператора
   * @param {string} operatorId 
   * @returns {SessionInfo[]}
   */
  getOperatorSessions(operatorId) {
    const sessionIds = this.operatorSessions.get(operatorId);
    if (!sessionIds) return [];
    
    return Array.from(sessionIds)
      .map(id => this.sessions.get(id))
      .filter(session => session !== undefined);
  }

  /**
   * Обновление состояния сессии
   * @param {string} sessionId 
   * @param {string} status 
   * @param {object} metadata 
   */
  updateSession(sessionId, status, metadata = {}) {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.updateStatus(status, metadata);
    }
  }

  /**
   * Завершение сессии
   * @param {string} sessionId 
   * @returns {SessionInfo|null}
   */
  closeSession(sessionId) {
    const session = this.sessions.get(sessionId);
    if (!session) return null;
    
    session.close();
    
    // Удаляем из устройства
    const deviceSessions = this.deviceSessions.get(session.deviceId);
    if (deviceSessions) {
      deviceSessions.delete(sessionId);
      if (deviceSessions.size === 0) {
        this.deviceSessions.delete(session.deviceId);
      }
    }
    
    // Удаляем из оператора
    const operatorSessions = this.operatorSessions.get(session.operatorId);
    if (operatorSessions) {
      operatorSessions.delete(sessionId);
      if (operatorSessions.size === 0) {
        this.operatorSessions.delete(session.operatorId);
      }
    }
    
    this.sessions.delete(sessionId);
    return session;
  }

  /**
   * Закрытие всех сессий устройства
   * @param {string} deviceId 
   */
  closeDeviceSessions(deviceId) {
    const sessions = this.getDeviceSessions(deviceId);
    sessions.forEach(session => this.closeSession(session.sessionId));
  }

  /**
   * Закрытие всех сессий оператора
   * @param {string} operatorId 
   */
  closeOperatorSessions(operatorId) {
    const sessions = this.getOperatorSessions(operatorId);
    sessions.forEach(session => this.closeSession(session.sessionId));
  }

  /**
   * Получение статистики
   * @returns {object}
   */
  getStats() {
    const sessions = Array.from(this.sessions.values());
    
    return {
      totalSessions: sessions.length,
      activeSessions: sessions.filter(s => s.status === 'active').length,
      pendingSessions: sessions.filter(s => s.status === 'pending').length,
      closedSessions: sessions.filter(s => s.status === 'closed').length,
      devices: this.deviceSessions.size,
      operators: this.operatorSessions.size,
      avgSessionDuration: this.calculateAverageSessionDuration(),
      sessionsByCamera: this.getSessionsByCameraType()
    };
  }

  /**
   * Расчет средней продолжительности сессий
   * @returns {number}
   */
  calculateAverageSessionDuration() {
    const closedSessions = Array.from(this.sessions.values())
      .filter(s => s.status === 'closed' && s.endTime);
    
    if (closedSessions.length === 0) return 0;
    
    const totalDuration = closedSessions.reduce((sum, session) => {
      return sum + (session.endTime - session.startTime);
    }, 0);
    
    return Math.round(totalDuration / closedSessions.length / 1000); // в секундах
  }

  /**
   * Статистика по типам камер
   * @returns {object}
   */
  getSessionsByCameraType() {
    const stats = {};
    Array.from(this.sessions.values()).forEach(session => {
      stats[session.cameraType] = (stats[session.cameraType] || 0) + 1;
    });
    return stats;
  }

  /**
   * Получение всех активных сессий
   * @returns {SessionInfo[]}
   */
  getActiveSessions() {
    return Array.from(this.sessions.values())
      .filter(session => session.status === 'active');
  }

  /**
   * Очистка старых закрытых сессий (старше N минут)
   * @param {number} maxAgeMinutes 
   */
  cleanupOldSessions(maxAgeMinutes = 60) {
    const cutoffTime = Date.now() - (maxAgeMinutes * 60 * 1000);
    const sessionsToRemove = [];
    
    for (const [sessionId, session] of this.sessions) {
      if (session.status === 'closed' && session.endTime < cutoffTime) {
        sessionsToRemove.push(sessionId);
      }
    }
    
    sessionsToRemove.forEach(sessionId => {
      const session = this.sessions.get(sessionId);
      if (session) {
        this.sessions.delete(sessionId);
        
        // Очистка из устройств и операторов
        const deviceSessions = this.deviceSessions.get(session.deviceId);
        if (deviceSessions) {
          deviceSessions.delete(sessionId);
        }
        
        const operatorSessions = this.operatorSessions.get(session.operatorId);
        if (operatorSessions) {
          operatorSessions.delete(sessionId);
        }
      }
    });
    
    return sessionsToRemove.length;
  }
}

class SessionInfo {
  constructor(sessionId, deviceId, operatorId, cameraType) {
    this.sessionId = sessionId;
    this.deviceId = deviceId;
    this.operatorId = operatorId;
    this.cameraType = cameraType;
    this.status = 'pending'; // pending, active, closed, error
    this.startTime = Date.now();
    this.endTime = null;
    this.metadata = {};
    this.events = [];
    this.webrtcState = null;
    this.quality = null;
    this.bandwidth = null;
  }

  /**
   * Обновление статуса сессии
   * @param {string} status 
   * @param {object} metadata 
   */
  updateStatus(status, metadata = {}) {
    this.status = status;
    this.metadata = { ...this.metadata, ...metadata };
    
    this.events.push({
      timestamp: Date.now(),
      event: 'status_change',
      data: { status, metadata }
    });

    if (status === 'active' && !this.startTime) {
      this.startTime = Date.now();
    }
  }

  /**
   * Обновление WebRTC состояния
   * @param {string} state 
   */
  updateWebRTCState(state) {
    this.webrtcState = state;
    this.events.push({
      timestamp: Date.now(),
      event: 'webrtc_state_change',
      data: { state }
    });
  }

  /**
   * Обновление качества потока
   * @param {object} qualityData 
   */
  updateQuality(qualityData) {
    this.quality = qualityData;
    this.events.push({
      timestamp: Date.now(),
      event: 'quality_update',
      data: qualityData
    });
  }

  /**
   * Смена типа камеры
   * @param {string} newCameraType 
   */
  switchCamera(newCameraType) {
    const oldType = this.cameraType;
    this.cameraType = newCameraType;
    
    this.events.push({
      timestamp: Date.now(),
      event: 'camera_switch',
      data: { from: oldType, to: newCameraType }
    });
  }

  /**
   * Закрытие сессии
   */
  close() {
    this.status = 'closed';
    this.endTime = Date.now();
    
    this.events.push({
      timestamp: Date.now(),
      event: 'session_closed',
      data: { duration: this.getDuration() }
    });
  }

  /**
   * Получение продолжительности сессии в миллисекундах
   * @returns {number}
   */
  getDuration() {
    const endTime = this.endTime || Date.now();
    return endTime - this.startTime;
  }

  /**
   * Получение человекочитаемой продолжительности
   * @returns {string}
   */
  getFormattedDuration() {
    const duration = this.getDuration();
    const seconds = Math.floor(duration / 1000) % 60;
    const minutes = Math.floor(duration / (1000 * 60)) % 60;
    const hours = Math.floor(duration / (1000 * 60 * 60));
    
    if (hours > 0) {
      return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  }

  /**
   * Получение сводки сессии
   * @returns {object}
   */
  getSummary() {
    return {
      sessionId: this.sessionId,
      deviceId: this.deviceId,
      operatorId: this.operatorId,
      cameraType: this.cameraType,
      status: this.status,
      duration: this.getFormattedDuration(),
      durationMs: this.getDuration(),
      startTime: new Date(this.startTime).toISOString(),
      endTime: this.endTime ? new Date(this.endTime).toISOString() : null,
      webrtcState: this.webrtcState,
      quality: this.quality,
      eventsCount: this.events.length
    };
  }

  /**
   * Получение полной информации о сессии
   * @returns {object}
   */
  getFullInfo() {
    return {
      ...this.getSummary(),
      metadata: this.metadata,
      events: this.events
    };
  }
}

module.exports = {
  SessionManager,
  SessionInfo
};