class DeviceManager {
  constructor() {
    this.devices = new Map(); // deviceId -> DeviceInfo
    this.operators = new Map(); // operatorId -> OperatorInfo
  }

  /**
   * Регистрация Android устройства
   * @param {string} deviceId 
   * @param {object} deviceInfo 
   * @param {object} socket 
   * @returns {DeviceInfo}
   */
  registerDevice(deviceId, deviceInfo, socket) {
    const device = new DeviceInfo(deviceId, deviceInfo, socket);
    this.devices.set(deviceId, device);
    return device;
  }

  /**
   * Регистрация оператора
   * @param {string} operatorId 
   * @param {object} operatorInfo 
   * @param {object} socket 
   * @returns {OperatorInfo}
   */
  registerOperator(operatorId, operatorInfo, socket) {
    const operator = new OperatorInfo(operatorId, operatorInfo, socket);
    this.operators.set(operatorId, operator);
    return operator;
  }

  /**
   * Получение устройства
   * @param {string} deviceId 
   * @returns {DeviceInfo|null}
   */
  getDevice(deviceId) {
    return this.devices.get(deviceId) || null;
  }

  /**
   * Получение оператора
   * @param {string} operatorId 
   * @returns {OperatorInfo|null}
   */
  getOperator(operatorId) {
    return this.operators.get(operatorId) || null;
  }

  /**
   * Получение всех подключенных устройств
   * @returns {DeviceInfo[]}
   */
  getConnectedDevices() {
    return Array.from(this.devices.values()).filter(device => device.isConnected());
  }

  /**
   * Получение всех подключенных операторов
   * @returns {OperatorInfo[]}
   */
  getConnectedOperators() {
    return Array.from(this.operators.values()).filter(operator => operator.isConnected());
  }

  /**
   * Получение доступных устройств для оператора
   * @param {string} operatorId 
   * @returns {DeviceInfo[]}
   */
  getAvailableDevicesForOperator(operatorId) {
    return this.getConnectedDevices().filter(device => {
      // Устройство доступно если оно подключено и не занято активной сессией
      return device.isConnected() && device.canAcceptNewSession();
    });
  }

  /**
   * Отключение устройства
   * @param {string} deviceId 
   */
  disconnectDevice(deviceId) {
    const device = this.devices.get(deviceId);
    if (device) {
      device.disconnect();
      this.devices.delete(deviceId);
    }
  }

  /**
   * Отключение оператора
   * @param {string} operatorId 
   */
  disconnectOperator(operatorId) {
    const operator = this.operators.get(operatorId);
    if (operator) {
      operator.disconnect();
      this.operators.delete(operatorId);
    }
  }

  /**
   * Обновление местоположения устройства
   * @param {string} deviceId 
   * @param {object} location 
   */
  updateDeviceLocation(deviceId, location) {
    const device = this.devices.get(deviceId);
    if (device) {
      device.updateLocation(location);
    }
  }

  /**
   * Обновление статуса устройства
   * @param {string} deviceId 
   * @param {string} status 
   */
  updateDeviceStatus(deviceId, status) {
    const device = this.devices.get(deviceId);
    if (device) {
      device.updateStatus(status);
    }
  }

  /**
   * Получение статистики
   * @returns {object}
   */
  getStats() {
    const devices = Array.from(this.devices.values());
    const operators = Array.from(this.operators.values());

    return {
      totalDevices: devices.length,
      connectedDevices: devices.filter(d => d.isConnected()).length,
      totalOperators: operators.length,
      connectedOperators: operators.filter(o => o.isConnected()).length,
      devicesByPlatform: this.getDevicesByPlatform(),
      devicesByStatus: this.getDevicesByStatus(),
      averageUptime: this.calculateAverageUptime()
    };
  }

  /**
   * Статистика устройств по платформе
   * @returns {object}
   */
  getDevicesByPlatform() {
    const stats = {};
    Array.from(this.devices.values()).forEach(device => {
      const platform = device.deviceInfo.manufacturer || 'unknown';
      stats[platform] = (stats[platform] || 0) + 1;
    });
    return stats;
  }

  /**
   * Статистика устройств по статусу
   * @returns {object}
   */
  getDevicesByStatus() {
    const stats = {};
    Array.from(this.devices.values()).forEach(device => {
      stats[device.status] = (stats[device.status] || 0) + 1;
    });
    return stats;
  }

  /**
   * Расчет среднего времени работы
   * @returns {number}
   */
  calculateAverageUptime() {
    const devices = Array.from(this.devices.values());
    if (devices.length === 0) return 0;

    const totalUptime = devices.reduce((sum, device) => sum + device.getUptime(), 0);
    return Math.round(totalUptime / devices.length / 1000); // в секундах
  }

  /**
   * Очистка отключенных устройств и операторов
   */
  cleanup() {
    // Удаляем отключенные устройства старше 5 минут
    const cutoffTime = Date.now() - (5 * 60 * 1000);
    
    for (const [deviceId, device] of this.devices) {
      if (!device.isConnected() && device.lastSeen < cutoffTime) {
        this.devices.delete(deviceId);
      }
    }

    for (const [operatorId, operator] of this.operators) {
      if (!operator.isConnected() && operator.lastSeen < cutoffTime) {
        this.operators.delete(operatorId);
      }
    }
  }
}

class DeviceInfo {
  constructor(deviceId, deviceInfo, socket) {
    this.deviceId = deviceId;
    this.deviceInfo = deviceInfo;
    this.socket = socket;
    this.status = 'connected';
    this.connectedAt = Date.now();
    this.lastSeen = Date.now();
    this.location = null;
    this.activeSessions = new Set();
    this.totalSessions = 0;
    this.capabilities = this.parseCapabilities(deviceInfo);
    this.healthCheck = {
      lastPing: Date.now(),
      responseTime: null,
      errors: 0
    };
  }

  /**
   * Парсинг возможностей устройства
   * @param {object} deviceInfo 
   * @returns {object}
   */
  parseCapabilities(deviceInfo) {
    const availableCameras = deviceInfo.availableCameras?.split(',') || ['back'];
    
    return {
      cameras: availableCameras,
      hasMultipleCameras: availableCameras.length > 1,
      hasUltraWide: availableCameras.includes('ultra_wide'),
      hasTelephoto: availableCameras.includes('telephoto'),
      supportedResolutions: deviceInfo.supportedResolutions || ['720p', '1080p'],
      maxConcurrentSessions: deviceInfo.maxConcurrentSessions || 1
    };
  }

  /**
   * Проверка подключения
   * @returns {boolean}
   */
  isConnected() {
    return this.socket && this.socket.connected && this.status === 'connected';
  }

  /**
   * Может ли устройство принять новую сессию
   * @returns {boolean}
   */
  canAcceptNewSession() {
    return this.isConnected() && 
           this.activeSessions.size < this.capabilities.maxConcurrentSessions &&
           this.status === 'connected';
  }

  /**
   * Добавление активной сессии
   * @param {string} sessionId 
   */
  addSession(sessionId) {
    this.activeSessions.add(sessionId);
    this.totalSessions++;
    this.updateStatus('busy');
  }

  /**
   * Удаление активной сессии
   * @param {string} sessionId 
   */
  removeSession(sessionId) {
    this.activeSessions.delete(sessionId);
    
    if (this.activeSessions.size === 0) {
      this.updateStatus('connected');
    }
  }

  /**
   * Обновление статуса
   * @param {string} status 
   */
  updateStatus(status) {
    this.status = status;
    this.lastSeen = Date.now();
  }

  /**
   * Обновление местоположения
   * @param {object} location 
   */
  updateLocation(location) {
    this.location = {
      latitude: location.latitude,
      longitude: location.longitude,
      accuracy: location.accuracy,
      timestamp: Date.now()
    };
  }

  /**
   * Отключение устройства
   */
  disconnect() {
    this.status = 'disconnected';
    this.lastSeen = Date.now();
  }

  /**
   * Получение времени работы
   * @returns {number}
   */
  getUptime() {
    return Date.now() - this.connectedAt;
  }

  /**
   * Обновление health check
   * @param {number} responseTime 
   */
  updateHealthCheck(responseTime) {
    this.healthCheck.lastPing = Date.now();
    this.healthCheck.responseTime = responseTime;
    this.healthCheck.errors = 0;
  }

  /**
   * Регистрация ошибки
   */
  recordError() {
    this.healthCheck.errors++;
  }

  /**
   * Получение сводки устройства
   * @returns {object}
   */
  getSummary() {
    return {
      deviceId: this.deviceId,
      deviceInfo: this.deviceInfo,
      status: this.status,
      isConnected: this.isConnected(),
      connectedAt: new Date(this.connectedAt).toISOString(),
      lastSeen: new Date(this.lastSeen).toISOString(),
      uptime: Math.round(this.getUptime() / 1000), // в секундах
      location: this.location,
      capabilities: this.capabilities,
      activeSessions: this.activeSessions.size,
      totalSessions: this.totalSessions,
      canAcceptSession: this.canAcceptNewSession(),
      healthCheck: this.healthCheck
    };
  }
}

class OperatorInfo {
  constructor(operatorId, operatorInfo, socket) {
    this.operatorId = operatorId;
    this.operatorInfo = operatorInfo || {};
    this.socket = socket;
    this.status = 'connected';
    this.connectedAt = Date.now();
    this.lastSeen = Date.now();
    this.activeSessions = new Set();
    this.totalSessions = 0;
    this.permissions = this.operatorInfo.permissions || ['view_cameras', 'request_camera'];
  }

  /**
   * Проверка подключения
   * @returns {boolean}
   */
  isConnected() {
    return this.socket && this.socket.connected && this.status === 'connected';
  }

  /**
   * Проверка разрешений
   * @param {string} permission 
   * @returns {boolean}
   */
  hasPermission(permission) {
    return this.permissions.includes(permission) || this.permissions.includes('admin');
  }

  /**
   * Добавление активной сессии
   * @param {string} sessionId 
   */
  addSession(sessionId) {
    this.activeSessions.add(sessionId);
    this.totalSessions++;
  }

  /**
   * Удаление активной сессии
   * @param {string} sessionId 
   */
  removeSession(sessionId) {
    this.activeSessions.delete(sessionId);
  }

  /**
   * Обновление последнего времени активности
   */
  updateActivity() {
    this.lastSeen = Date.now();
  }

  /**
   * Отключение оператора
   */
  disconnect() {
    this.status = 'disconnected';
    this.lastSeen = Date.now();
  }

  /**
   * Получение времени работы
   * @returns {number}
   */
  getUptime() {
    return Date.now() - this.connectedAt;
  }

  /**
   * Получение сводки оператора
   * @returns {object}
   */
  getSummary() {
    return {
      operatorId: this.operatorId,
      operatorInfo: this.operatorInfo,
      status: this.status,
      isConnected: this.isConnected(),
      connectedAt: new Date(this.connectedAt).toISOString(),
      lastSeen: new Date(this.lastSeen).toISOString(),
      uptime: Math.round(this.getUptime() / 1000), // в секундах
      activeSessions: this.activeSessions.size,
      totalSessions: this.totalSessions,
      permissions: this.permissions
    };
  }
}

module.exports = {
  DeviceManager,
  DeviceInfo,
  OperatorInfo
};