// Admin Console Connector - REST API for policy synchronization
// Handles configuration push/pull from centralized admin console

export class AdminConsoleConnector {
  constructor(config = {}) {
    this.config = config;
    this.enabled = config.adminConsoleEnabled || false;
    this.baseUrl = config.adminConsoleUrl;
    this.apiKey = config.adminConsoleApiKey;
    this.organizationId = config.organizationId;
    this.deviceId = null;
    this.lastSyncTime = null;
    this.syncInterval = config.adminConsoleSyncInterval || 1800000; // 30 minutes default
    this.retryAttempts = 0;
    this.maxRetries = config.maxRetries || 3;
  }

  /**
   * Initialize admin console connector
   */
  async initialize() {
    if (!this.enabled) {
      console.log('Admin console connector disabled');
      return false;
    }

    if (!this.baseUrl) {
      console.error('Admin console URL not configured');
      return false;
    }

    // Generate or retrieve device ID
    this.deviceId = await this.getOrCreateDeviceId();

    // Register device with admin console
    const registered = await this.registerDevice();

    if (!registered) {
      console.error('Failed to register device with admin console');
      return false;
    }

    // Initial configuration sync
    await this.syncConfiguration();

    // Start periodic sync
    this.startPeriodicSync();

    console.log('Admin console connector initialized successfully');
    return true;
  }

  /**
   * Get or create device ID
   * @returns {string} - Device ID
   */
  async getOrCreateDeviceId() {
    try {
      const result = await chrome.storage.local.get(['deviceId']);

      if (result.deviceId) {
        return result.deviceId;
      }

      // Generate new device ID
      const deviceId = this.generateDeviceId();

      await chrome.storage.local.set({ deviceId });

      return deviceId;
    } catch (error) {
      console.error('Failed to get/create device ID:', error);
      return this.generateDeviceId();
    }
  }

  /**
   * Generate unique device ID
   * @returns {string} - Device ID
   */
  generateDeviceId() {
    const timestamp = Date.now().toString(36);
    const random = Math.random().toString(36).substring(2, 15);
    return `device_${timestamp}_${random}`;
  }

  /**
   * Register device with admin console
   */
  async registerDevice() {
    try {
      const response = await this.apiRequest('POST', '/devices/register', {
        deviceId: this.deviceId,
        organizationId: this.organizationId,
        extensionVersion: chrome.runtime.getManifest().version,
        browser: this.getBrowserInfo(),
        registeredAt: Date.now()
      });

      if (response.success) {
        console.log('Device registered successfully');
        return true;
      } else {
        console.error('Device registration failed:', response.error);
        return false;
      }
    } catch (error) {
      console.error('Failed to register device:', error);
      return false;
    }
  }

  /**
   * Sync configuration from admin console
   */
  async syncConfiguration() {
    try {
      console.log('Syncing configuration from admin console...');

      const response = await this.apiRequest('GET', `/devices/${this.deviceId}/config`);

      if (!response.success) {
        console.error('Configuration sync failed:', response.error);
        return null;
      }

      const config = response.data;

      // Validate configuration
      const validation = this.validateConfiguration(config);

      if (!validation.valid) {
        console.error('Invalid configuration received:', validation.errors);
        return null;
      }

      // Apply configuration
      await this.applyConfiguration(config);

      this.lastSyncTime = Date.now();
      this.retryAttempts = 0; // Reset retry counter on success

      console.log('Configuration synced successfully');
      return config;
    } catch (error) {
      console.error('Failed to sync configuration:', error);

      // Retry logic
      if (this.retryAttempts < this.maxRetries) {
        this.retryAttempts++;
        const retryDelay = Math.min(1000 * Math.pow(2, this.retryAttempts), 30000);
        console.log(`Retrying in ${retryDelay}ms (attempt ${this.retryAttempts}/${this.maxRetries})`);

        setTimeout(() => this.syncConfiguration(), retryDelay);
      }

      return null;
    }
  }

  /**
   * Apply configuration from admin console
   * @param {object} config - Configuration to apply
   */
  async applyConfiguration(config) {
    // Apply policy
    if (config.policy) {
      console.log('Applying policy from admin console');
      this.dispatchConfigUpdate('policy', config.policy);
    }

    // Apply detector configuration
    if (config.detectors) {
      console.log('Applying detector configuration');
      this.dispatchConfigUpdate('detectors', config.detectors);
    }

    // Apply risk thresholds
    if (config.riskThresholds) {
      console.log('Applying risk thresholds');
      this.dispatchConfigUpdate('riskThresholds', config.riskThresholds);
    }

    // Apply telemetry settings
    if (config.telemetry) {
      console.log('Applying telemetry settings');
      this.dispatchConfigUpdate('telemetry', config.telemetry);
    }

    // Apply audit settings
    if (config.audit) {
      console.log('Applying audit settings');
      this.dispatchConfigUpdate('audit', config.audit);
    }

    // Apply SIEM settings
    if (config.siem) {
      console.log('Applying SIEM settings');
      this.dispatchConfigUpdate('siem', config.siem);
    }

    // Apply feature flags
    if (config.features) {
      console.log('Applying feature flags');
      this.dispatchConfigUpdate('features', config.features);
    }

    // Save configuration locally
    await chrome.storage.local.set({
      adminConsoleConfig: config,
      adminConsoleConfigTimestamp: Date.now()
    });
  }

  /**
   * Push telemetry metrics to admin console
   * @param {object} metrics - Telemetry metrics
   */
  async pushMetrics(metrics) {
    try {
      const response = await this.apiRequest('POST', `/devices/${this.deviceId}/metrics`, {
        metrics,
        timestamp: Date.now()
      });

      if (response.success) {
        console.log('Metrics pushed successfully');
        return true;
      } else {
        console.error('Failed to push metrics:', response.error);
        return false;
      }
    } catch (error) {
      console.error('Error pushing metrics:', error);
      return false;
    }
  }

  /**
   * Push audit logs to admin console
   * @param {array} logs - Audit logs
   */
  async pushAuditLogs(logs) {
    try {
      const response = await this.apiRequest('POST', `/devices/${this.deviceId}/audit-logs`, {
        logs,
        timestamp: Date.now()
      });

      if (response.success) {
        console.log('Audit logs pushed successfully');
        return true;
      } else {
        console.error('Failed to push audit logs:', response.error);
        return false;
      }
    } catch (error) {
      console.error('Error pushing audit logs:', error);
      return false;
    }
  }

  /**
   * Push detection events to admin console
   * @param {object} detection - Detection event
   */
  async pushDetectionEvent(detection) {
    try {
      const response = await this.apiRequest('POST', `/devices/${this.deviceId}/detections`, {
        detection,
        timestamp: Date.now()
      });

      if (response.success) {
        return true;
      } else {
        console.error('Failed to push detection:', response.error);
        return false;
      }
    } catch (error) {
      console.error('Error pushing detection:', error);
      return false;
    }
  }

  /**
   * Fetch policy from admin console
   * @returns {object} - Policy configuration
   */
  async fetchPolicy() {
    try {
      const response = await this.apiRequest('GET', `/organizations/${this.organizationId}/policy`);

      if (response.success) {
        return response.data;
      } else {
        console.error('Failed to fetch policy:', response.error);
        return null;
      }
    } catch (error) {
      console.error('Error fetching policy:', error);
      return null;
    }
  }

  /**
   * Report device status to admin console
   * @param {object} status - Device status
   */
  async reportStatus(status) {
    try {
      const response = await this.apiRequest('POST', `/devices/${this.deviceId}/status`, {
        status,
        timestamp: Date.now()
      });

      if (response.success) {
        console.log('Status reported successfully');
        return true;
      } else {
        console.error('Failed to report status:', response.error);
        return false;
      }
    } catch (error) {
      console.error('Error reporting status:', error);
      return false;
    }
  }

  /**
   * Make API request to admin console
   * @param {string} method - HTTP method
   * @param {string} endpoint - API endpoint
   * @param {object} data - Request data
   * @returns {object} - Response data
   */
  async apiRequest(method, endpoint, data = null) {
    const url = `${this.baseUrl}${endpoint}`;

    const headers = {
      'Content-Type': 'application/json',
      'X-API-Key': this.apiKey,
      'X-Device-ID': this.deviceId,
      'X-Organization-ID': this.organizationId,
      'X-Extension-Version': chrome.runtime.getManifest().version
    };

    const options = {
      method,
      headers
    };

    if (data && (method === 'POST' || method === 'PUT')) {
      options.body = JSON.stringify(data);
    }

    try {
      const response = await fetch(url, options);

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const responseData = await response.json();
      return responseData;
    } catch (error) {
      console.error(`API request failed: ${method} ${endpoint}`, error);
      throw error;
    }
  }

  /**
   * Dispatch configuration update event
   * @param {string} category - Configuration category
   * @param {object} data - Configuration data
   */
  dispatchConfigUpdate(category, data) {
    if (chrome.runtime && chrome.runtime.sendMessage) {
      chrome.runtime.sendMessage({
        type: 'admin-console-config-update',
        category,
        data,
        source: 'admin-console'
      }).catch(error => {
        console.warn('Failed to dispatch config update:', error);
      });
    }
  }

  /**
   * Validate configuration
   * @param {object} config - Configuration to validate
   * @returns {object} - Validation result
   */
  validateConfiguration(config) {
    const errors = [];

    // Basic structure validation
    if (!config || typeof config !== 'object') {
      errors.push('Configuration must be an object');
      return { valid: false, errors };
    }

    // Validate policy
    if (config.policy) {
      if (!config.policy.version) {
        errors.push('Policy must have a version');
      }
      if (!config.policy.rules && !config.policy.defaultRule) {
        errors.push('Policy must have rules or defaultRule');
      }
    }

    // Validate risk thresholds
    if (config.riskThresholds) {
      const { critical, high, medium, low } = config.riskThresholds;
      if (critical !== undefined && (critical < 0 || critical > 100)) {
        errors.push('Invalid risk threshold: critical');
      }
      if (high !== undefined && (high < 0 || high > 100)) {
        errors.push('Invalid risk threshold: high');
      }
      if (medium !== undefined && (medium < 0 || medium > 100)) {
        errors.push('Invalid risk threshold: medium');
      }
      if (low !== undefined && (low < 0 || low > 100)) {
        errors.push('Invalid risk threshold: low');
      }
    }

    // Validate detector configuration
    if (config.detectors) {
      if (config.detectors.enabled && !Array.isArray(config.detectors.enabled)) {
        errors.push('detectors.enabled must be an array');
      }
      if (config.detectors.disabled && !Array.isArray(config.detectors.disabled)) {
        errors.push('detectors.disabled must be an array');
      }
    }

    return {
      valid: errors.length === 0,
      errors
    };
  }

  /**
   * Get browser information
   * @returns {object} - Browser info
   */
  getBrowserInfo() {
    const userAgent = navigator.userAgent;
    let browser = 'unknown';
    let version = 'unknown';

    if (userAgent.includes('Chrome')) {
      browser = 'chrome';
      const match = userAgent.match(/Chrome\/(\d+)/);
      version = match ? match[1] : 'unknown';
    } else if (userAgent.includes('Firefox')) {
      browser = 'firefox';
      const match = userAgent.match(/Firefox\/(\d+)/);
      version = match ? match[1] : 'unknown';
    } else if (userAgent.includes('Edge')) {
      browser = 'edge';
      const match = userAgent.match(/Edge\/(\d+)/);
      version = match ? match[1] : 'unknown';
    }

    return {
      name: browser,
      version,
      userAgent
    };
  }

  /**
   * Start periodic configuration sync
   */
  startPeriodicSync() {
    if (this.syncIntervalId) {
      clearInterval(this.syncIntervalId);
    }

    this.syncIntervalId = setInterval(async () => {
      await this.syncConfiguration();
    }, this.syncInterval);
  }

  /**
   * Stop periodic sync
   */
  stopPeriodicSync() {
    if (this.syncIntervalId) {
      clearInterval(this.syncIntervalId);
      this.syncIntervalId = null;
    }
  }

  /**
   * Force immediate configuration sync
   */
  async forceSyncConfiguration() {
    console.log('Force syncing configuration from admin console...');
    return await this.syncConfiguration();
  }

  /**
   * Get connection status
   * @returns {object} - Connection status
   */
  getConnectionStatus() {
    return {
      enabled: this.enabled,
      connected: this.lastSyncTime !== null,
      lastSyncTime: this.lastSyncTime,
      baseUrl: this.baseUrl,
      organizationId: this.organizationId,
      deviceId: this.deviceId,
      retryAttempts: this.retryAttempts
    };
  }

  /**
   * Test connection to admin console
   */
  async testConnection() {
    try {
      const response = await this.apiRequest('GET', '/health');
      return response.success === true;
    } catch (error) {
      console.error('Connection test failed:', error);
      return false;
    }
  }

  /**
   * Clean up and stop connector
   */
  cleanup() {
    this.stopPeriodicSync();
    console.log('Admin console connector cleaned up');
  }
}
