Source: frontend/js/services/VSOMService.js

import log from 'loglevel';

/**
 * Service for interacting with the VSOM API
 * Handles all VSOM-related API calls and data transformation
 */
export class VSOMService {
  constructor(options = {}) {
    this.logger = log.getLogger('vsom:service');
    this.defaultOptions = {
      baseUrl: '/api/vsom',
      logLevel: 'debug',
      ...options
    };
    
    this.logger.setLevel(this.defaultOptions.logLevel);
    this.logger.debug('Initializing VSOM service', { options: this.defaultOptions });
    
    // Initialize default headers
    this.headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };
  }

  /**
   * Make an API request
   * @private
   */
  async _request(method, endpoint, data = null) {
    const url = `${this.defaultOptions.baseUrl}${endpoint}`;
    const startTime = performance.now();
    
    const config = {
      method,
      headers: this.headers,
      credentials: 'same-origin',
      ...(data && { body: JSON.stringify(data) })
    };
    
    this.logger.debug(`API ${method} ${endpoint}`, { data });
    
    try {
      const response = await fetch(url, config);
      const responseTime = performance.now() - startTime;
      
      if (!response.ok) {
        const errorData = await this._parseResponse(response);
        const error = new Error(errorData.message || `HTTP error! status: ${response.status}`);
        error.status = response.status;
        error.data = errorData;
        this.logger.error(`API error ${response.status} ${method} ${endpoint}`, {
          status: response.status,
          statusText: response.statusText,
          response: errorData,
          duration: responseTime
        });
        throw error;
      }
      
      const result = await this._parseResponse(response);
      this.logger.debug(`API success ${method} ${endpoint}`, {
        status: response.status,
        duration: responseTime,
        data: result
      });
      
      return result;
    } catch (error) {
      const responseTime = performance.now() - startTime;
      this.logger.error(`API request failed: ${method} ${endpoint}`, {
        error,
        duration: responseTime
      });
      throw error;
    }
  }

  /**
   * Parse API response
   * @private
   */
  async _parseResponse(response) {
    const contentType = response.headers.get('content-type');
    if (contentType && contentType.includes('application/json')) {
      return response.json();
    }
    return response.text();
  }

  // VSOM API Methods

  /**
   * Create a new SOM instance
   * @param {Object} config - SOM configuration
   */
  async createSOM(config) {
    this.logger.debug('Creating new SOM instance', { config });
    return this._request('POST', '/create', config);
  }

  /**
   * Train the SOM with data
   * @param {Array} data - Training data
   * @param {Object} options - Training options
   */
  async train(data, options = {}) {
    this.logger.debug('Training SOM', { dataLength: data.length, options });
    return this._request('POST', '/train', { data, ...options });
  }

  /**
   * Get the current SOM grid state
   * @param {Object} options - Query options
   */
  async getGridState(options = {}) {
    this.logger.debug('Fetching SOM grid state', { options });
    const query = new URLSearchParams(options).toString();
    return this._request('GET', `/grid${query ? `?${query}` : ''}`);
  }

  /**
   * Get feature maps
   * @param {Object} options - Query options
   */
  async getFeatureMaps(options = {}) {
    this.logger.debug('Fetching feature maps', { options });
    const query = new URLSearchParams(options).toString();
    return this._request('GET', `/features${query ? `?${query}` : ''}`);
  }

  /**
   * Perform clustering on the SOM
   * @param {Object} options - Clustering options
   */
  async cluster(options = {}) {
    this.logger.debug('Performing clustering', { options });
    return this._request('POST', '/cluster', options);
  }

  /**
   * Get training status
   */
  async getTrainingStatus() {
    this.logger.debug('Fetching training status');
    return this._request('GET', '/training-status');
  }

  /**
   * Stop ongoing training
   */
  async stopTraining() {
    this.logger.debug('Stopping training');
    return this._request('POST', '/stop-training');
  }

  /**
   * Load data into VSOM
   * @param {Object} data - Data to load
   */
  async loadData(data) {
    this.logger.debug('Loading data into VSOM', { data });
    return this._request('POST', '/load-data', data);
  }

  /**
   * Generate sample data for testing
   * @param {number} count - Number of sample entities to generate
   */
  async generateSampleData(count = 50) {
    this.logger.debug('Generating sample data', { count });
    return this._request('POST', '/generate-sample-data', { count });
  }
}

// Export a singleton instance
export const vsomService = new VSOMService();