/**
 * Утилита для создания уникального отпечатка устройства (Device Fingerprinting)
 * Используется для блокировки на уровне железа
 */

class DeviceFingerprint {
  constructor() {
    this.components = new Map();
    this.fingerprint = null;
    this.initialized = false;
  }

  /**
   * Инициализация и создание отпечатка устройства
   */
  async initialize() {
    try {
      console.log('[DeviceFingerprint] Начинаем инициализацию отпечатка устройства...');
      
      // Очищаем предыдущие компоненты
      this.components.clear();
      
      // Собираем компоненты отпечатка
      await this.collectScreenInfo();
      await this.collectNavigatorInfo();
      await this.collectCanvasFingerprint();
      await this.collectWebGLFingerprint();
      await this.collectAudioFingerprint();
      await this.collectTimezoneInfo();
      await this.collectLanguageInfo();
      await this.collectPlatformInfo();
      await this.collectHardwareInfo();
      await this.collectStorageInfo();
      await this.collectNetworkInfo();
      
      // Генерируем финальный отпечаток
      this.fingerprint = await this.generateFingerprint();
      this.initialized = true;
      
      console.log('[DeviceFingerprint] Отпечаток устройства создан:', this.fingerprint.substring(0, 16) + '...');
      return this.fingerprint;
      
    } catch (error) {
      console.error('[DeviceFingerprint] Ошибка при создании отпечатка:', error);
      // Создаем базовый отпечаток даже при ошибках
      this.fingerprint = await this.createFallbackFingerprint();
      this.initialized = true;
      return this.fingerprint;
    }
  }

  /**
   * Информация об экране
   */
  async collectScreenInfo() {
    try {
      this.components.set('screen', {
        width: screen.width,
        height: screen.height,
        availWidth: screen.availWidth,
        availHeight: screen.availHeight,
        colorDepth: screen.colorDepth,
        pixelDepth: screen.pixelDepth,
        devicePixelRatio: window.devicePixelRatio || 1
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить информацию об экране:', e);
    }
  }

  /**
   * Информация о навигаторе
   */
  async collectNavigatorInfo() {
    try {
      this.components.set('navigator', {
        userAgent: navigator.userAgent,
        language: navigator.language,
        languages: navigator.languages ? Array.from(navigator.languages) : [],
        platform: navigator.platform,
        cookieEnabled: navigator.cookieEnabled,
        doNotTrack: navigator.doNotTrack,
        maxTouchPoints: navigator.maxTouchPoints || 0,
        hardwareConcurrency: navigator.hardwareConcurrency || 0,
        deviceMemory: navigator.deviceMemory || 0
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить информацию навигатора:', e);
    }
  }

  /**
   * Canvas fingerprinting
   */
  async collectCanvasFingerprint() {
    try {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      
      // Рисуем уникальный паттерн
      ctx.textBaseline = 'top';
      ctx.font = '14px Arial';
      ctx.fillStyle = '#f60';
      ctx.fillRect(125, 1, 62, 20);
      ctx.fillStyle = '#069';
      ctx.fillText('Device fingerprint text 🔐', 2, 15);
      ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
      ctx.fillText('Device fingerprint text 🔐', 4, 17);
      
      // Добавляем геометрические фигуры
      ctx.globalCompositeOperation = 'multiply';
      ctx.fillStyle = 'rgb(255,0,255)';
      ctx.beginPath();
      ctx.arc(50, 50, 50, 0, Math.PI * 2, true);
      ctx.closePath();
      ctx.fill();
      
      const canvasData = canvas.toDataURL();
      this.components.set('canvas', this.hashString(canvasData));
      
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось создать canvas fingerprint:', e);
    }
  }

  /**
   * WebGL fingerprinting
   */
  async collectWebGLFingerprint() {
    try {
      const canvas = document.createElement('canvas');
      const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
      
      if (gl) {
        const webglInfo = {
          version: gl.getParameter(gl.VERSION),
          vendor: gl.getParameter(gl.VENDOR),
          renderer: gl.getParameter(gl.RENDERER),
          shadingLanguageVersion: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
          maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
          maxViewportDims: gl.getParameter(gl.MAX_VIEWPORT_DIMS)
        };
        
        this.components.set('webgl', webglInfo);
      }
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить WebGL информацию:', e);
    }
  }

  /**
   * Audio fingerprinting
   */
  async collectAudioFingerprint() {
    return new Promise((resolve) => {
      try {
        if (!window.AudioContext && !window.webkitAudioContext) {
          resolve();
          return;
        }
        
        const AudioContext = window.AudioContext || window.webkitAudioContext;
        const context = new AudioContext();
        
        const oscillator = context.createOscillator();
        const analyser = context.createAnalyser();
        const gainNode = context.createGain();
        const scriptProcessor = context.createScriptProcessor(4096, 1, 1);
        
        oscillator.type = 'triangle';
        oscillator.frequency.value = 10000;
        
        gainNode.gain.value = 0;
        
        oscillator.connect(analyser);
        analyser.connect(scriptProcessor);
        scriptProcessor.connect(gainNode);
        gainNode.connect(context.destination);
        
        scriptProcessor.onaudioprocess = (event) => {
          const bins = new Float32Array(analyser.frequencyBinCount);
          analyser.getFloatFrequencyData(bins);
          
          const audioHash = this.hashString(bins.slice(0, 50).join(','));
          this.components.set('audio', audioHash);
          
          oscillator.disconnect();
          context.close();
          resolve();
        };
        
        oscillator.start();
        
        // Таймаут на случай проблем
        setTimeout(() => {
          try {
            oscillator.disconnect();
            context.close();
          } catch (e) {}
          resolve();
        }, 1000);
        
      } catch (e) {
        console.warn('[DeviceFingerprint] Не удалось создать audio fingerprint:', e);
        resolve();
      }
    });
  }

  /**
   * Информация о временной зоне
   */
  async collectTimezoneInfo() {
    try {
      this.components.set('timezone', {
        timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
        timezoneOffset: new Date().getTimezoneOffset(),
        locale: Intl.DateTimeFormat().resolvedOptions().locale
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить информацию о временной зоне:', e);
    }
  }

  /**
   * Языковые настройки
   */
  async collectLanguageInfo() {
    try {
      this.components.set('language', {
        language: navigator.language,
        languages: navigator.languages ? Array.from(navigator.languages) : []
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить языковую информацию:', e);
    }
  }

  /**
   * Платформа и ОС
   */
  async collectPlatformInfo() {
    try {
      this.components.set('platform', {
        platform: navigator.platform,
        oscpu: navigator.oscpu,
        appVersion: navigator.appVersion
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить информацию о платформе:', e);
    }
  }

  /**
   * Аппаратная информация
   */
  async collectHardwareInfo() {
    try {
      this.components.set('hardware', {
        hardwareConcurrency: navigator.hardwareConcurrency || 0,
        deviceMemory: navigator.deviceMemory || 0,
        maxTouchPoints: navigator.maxTouchPoints || 0
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить аппаратную информацию:', e);
    }
  }

  /**
   * Информация о хранилище
   */
  async collectStorageInfo() {
    try {
      let storageQuota = 0;
      if ('storage' in navigator && 'estimate' in navigator.storage) {
        const estimate = await navigator.storage.estimate();
        storageQuota = estimate.quota || 0;
      }
      
      this.components.set('storage', {
        localStorage: !!window.localStorage,
        sessionStorage: !!window.sessionStorage,
        indexedDB: !!window.indexedDB,
        storageQuota
      });
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить информацию о хранилище:', e);
    }
  }

  /**
   * Сетевая информация
   */
  async collectNetworkInfo() {
    try {
      const networkInfo = {};
      
      if ('connection' in navigator) {
        const conn = navigator.connection;
        networkInfo.effectiveType = conn.effectiveType;
        networkInfo.downlink = conn.downlink;
        networkInfo.rtt = conn.rtt;
      }
      
      this.components.set('network', networkInfo);
    } catch (e) {
      console.warn('[DeviceFingerprint] Не удалось получить сетевую информацию:', e);
    }
  }

  /**
   * Генерация финального отпечатка
   */
  async generateFingerprint() {
    const componentsString = JSON.stringify(Array.from(this.components.entries()).sort());
    return await this.hashString(componentsString);
  }

  /**
   * Создание резервного отпечатка при ошибках
   */
  async createFallbackFingerprint() {
    const fallbackData = {
      userAgent: navigator.userAgent,
      screen: `${screen.width}x${screen.height}`,
      timezone: new Date().getTimezoneOffset(),
      language: navigator.language,
      timestamp: Date.now()
    };
    
    return await this.hashString(JSON.stringify(fallbackData));
  }

  /**
   * Хеширование строки
   */
  async hashString(str) {
    if (crypto && crypto.subtle) {
      const encoder = new TextEncoder();
      const data = encoder.encode(str);
      const hashBuffer = await crypto.subtle.digest('SHA-256', data);
      const hashArray = Array.from(new Uint8Array(hashBuffer));
      return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    } else {
      // Fallback для старых браузеров
      return this.simpleHash(str);
    }
  }

  /**
   * Простое хеширование для старых браузеров
   */
  simpleHash(str) {
    let hash = 0;
    if (str.length === 0) return hash.toString();
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // Конвертируем в 32-битное целое
    }
    return Math.abs(hash).toString(16);
  }

  /**
   * Получение текущего отпечатка
   */
  getFingerprint() {
    return this.fingerprint;
  }

  /**
   * Проверка инициализации
   */
  isInitialized() {
    return this.initialized;
  }

  /**
   * Получение компонентов отпечатка (для отладки)
   */
  getComponents() {
    return Object.fromEntries(this.components);
  }

  /**
   * Обновление отпечатка
   */
  async refresh() {
    return await this.initialize();
  }
}

// Экспортируем класс
export default DeviceFingerprint;