/**
 * META-AWARE COMPONENT
 *
 * STRUCTURAL PATTERN: Observer (Publish-Subscribe)
 * ABSTRACTION LEVEL: High
 * COMPLEXITY: 5/10
 *
 * PURPOSE: State management with explicit observer pattern and meta-level tracking
 * WHY THIS PATTERN: Observer pattern decouples state changes from reactions, enabling
 *                    extensible event-driven architectures with clear dependency flow
 *
 * QUALITY SELF-ASSESSMENT:
 * - Structural Clarity: 9/10 (clean separation of concerns, clear interfaces)
 * - Meta-Awareness: 8/10 (tracks subscriptions, measures notification patterns)
 * - Evolution Potential: 7/10 (can add filtering, priority, async notifications)
 * - Pattern Generalizability: 10/10 (observer pattern is universally applicable)
 * - Self-Documentation Quality: 9/10 (extensive pattern annotations)
 *
 * IMPROVEMENT SUGGESTIONS:
 * 1. Add subscription filtering (observers only notified for specific state keys)
 * 2. Implement priority levels for observers (critical vs optional notifications)
 * 3. Add async notification support with error handling and retry logic
 *
 * EVOLUTION PATH:
 * - Next step: Add event filtering to reduce unnecessary notifications
 * - Long-term: Evolve into full reactive state management with computed properties
 */

// === IMPLEMENTATION ===

class MetaAwareObservableState {
  constructor(initialState = {}) {
    // Core state
    this._state = { ...initialState };

    // Observer registry: Map<observerId, callback>
    this._observers = new Map();

    // Meta-tracking
    this._metrics = {
      stateChanges: 0,
      notifications: 0,
      observerCount: 0,
      subscriptionHistory: [],
      notificationHistory: []
    };

    this._nextObserverId = 1;
  }

  /**
   * Subscribe to state changes
   * Pattern: Observer registration
   */
  subscribe(callback, metadata = {}) {
    const observerId = this._nextObserverId++;
    this._observers.set(observerId, callback);

    // Meta-tracking: record subscription
    this._metrics.observerCount = this._observers.size;
    this._metrics.subscriptionHistory.push({
      observerId,
      timestamp: Date.now(),
      metadata
    });

    console.log(`[META] Observer ${observerId} subscribed. Total observers: ${this._observers.size}`);

    // Return unsubscribe function (functional pattern)
    return () => this.unsubscribe(observerId);
  }

  /**
   * Unsubscribe from state changes
   * Pattern: Observer deregistration
   */
  unsubscribe(observerId) {
    const existed = this._observers.delete(observerId);
    if (existed) {
      this._metrics.observerCount = this._observers.size;
      console.log(`[META] Observer ${observerId} unsubscribed. Total observers: ${this._observers.size}`);
    }
    return existed;
  }

  /**
   * Get current state (immutable copy)
   * Pattern: Encapsulation
   */
  getState() {
    return { ...this._state };
  }

  /**
   * Update state and notify observers
   * Pattern: State mutation + notification broadcast
   */
  setState(updates) {
    // Record previous state for change detection
    const prevState = { ...this._state };

    // Apply updates
    this._state = { ...this._state, ...updates };

    // Meta-tracking
    this._metrics.stateChanges++;
    const changedKeys = Object.keys(updates);

    console.log(`[META] State updated. Changed keys: ${changedKeys.join(', ')}`);

    // Notify all observers
    this._notifyObservers(prevState, this._state, changedKeys);
  }

  /**
   * Notify all observers of state change
   * Pattern: Broadcast notification
   */
  _notifyObservers(prevState, newState, changedKeys) {
    const notificationStart = Date.now();
    let successCount = 0;
    let errorCount = 0;

    this._observers.forEach((callback, observerId) => {
      try {
        callback(newState, prevState, changedKeys);
        successCount++;
        this._metrics.notifications++;
      } catch (error) {
        errorCount++;
        console.error(`[META] Observer ${observerId} error:`, error.message);
      }
    });

    const duration = Date.now() - notificationStart;

    // Meta-tracking: record notification batch
    this._metrics.notificationHistory.push({
      timestamp: Date.now(),
      observerCount: this._observers.size,
      successCount,
      errorCount,
      duration,
      changedKeys
    });

    console.log(`[META] Notified ${successCount} observers in ${duration}ms (${errorCount} errors)`);
  }

  /**
   * Get meta-metrics about observer pattern usage
   * Pattern: Introspection
   */
  getMetrics() {
    return {
      ...this._metrics,
      currentObservers: this._observers.size,
      pattern: 'Observer (Pub-Sub)',
      avgNotificationsPerChange: this._metrics.stateChanges > 0
        ? (this._metrics.notifications / this._metrics.stateChanges).toFixed(2)
        : 0
    };
  }
}

// === STRUCTURAL REFLECTION ===
// Pattern Used: Observer (Publish-Subscribe)
// Why: Decouples state management from state reactions, enabling flexible
//      event-driven architectures. Multiple components can react to state
//      changes without tight coupling.
// Trade-offs:
//   - Memory overhead: stores all observer callbacks
//   - Potential for notification storms if many observers
//   - No built-in filtering (all observers notified of all changes)
//   - Synchronous notifications can block state updates

// === META-ANALYSIS ===
// What worked well:
//   - Clear separation: state storage, observer management, notification
//   - Functional unsubscribe pattern prevents memory leaks
//   - Comprehensive meta-tracking validates pattern behavior
//   - Immutable state copies prevent unintended mutations
// What could improve:
//   - Add event filtering (observers specify which keys they care about)
//   - Implement async notifications to prevent blocking
//   - Add priority system for critical vs optional observers
//   - Batching support for multiple rapid state changes
// Generalizability:
//   - This observer pattern applies to: event systems, UI reactivity,
//     data binding, plugin architectures, middleware chains, stream processing

// === USAGE EXAMPLE ===
const state = new MetaAwareObservableState({ count: 0, name: 'Test' });

// Subscribe observers
const unsubscribe1 = state.subscribe((newState, prevState, changedKeys) => {
  console.log('Observer 1: state changed', changedKeys);
});

const unsubscribe2 = state.subscribe((newState, prevState) => {
  console.log('Observer 2: count is now', newState.count);
});

// Trigger state changes
state.setState({ count: 1 }); // Both observers notified
state.setState({ count: 2, name: 'Updated' }); // Both observers notified

// Unsubscribe one observer
unsubscribe1();

state.setState({ count: 3 }); // Only observer 2 notified

console.log('Metrics:', state.getMetrics());

module.exports = MetaAwareObservableState;
