# ⚡ Реактивность и Live Queries в CSElement

Реактивность - это сердце CSElement. Система автоматически отслеживает изменения и обновляет зависимые данные, делая ваши приложения отзывчивыми и современными.

## 🎯 Основы реактивности

### Что такое реактивность?

Реактивность означает, что когда данные изменяются, все зависимые от них компоненты обновляются автоматически.

```typescript
import { CSElement } from 'cs-element';

// Создаем реактивную структуру
const store = CSElement.create('Store')
  .withData('count', 0)
  .withData('multiplier', 2);

// Создаем computed свойство
const doubledCount = CSElement.computed(() => {
  return store.getData('count') * store.getData('multiplier');
});

console.log('Удвоенное значение:', doubledCount.value); // 0

// Изменяем данные - computed автоматически пересчитается
await store.setData('count', 5);
console.log('Удвоенное значение:', doubledCount.value); // 10

await store.setData('multiplier', 3);
console.log('Удвоенное значение:', doubledCount.value); // 15
```

### Отслеживание изменений с watch

```typescript
// Отслеживаем изменения конкретного поля
CSElement.watch([store.id, 'count'], (newValue, oldValue) => {
  console.log(`Счетчик изменился: ${oldValue} → ${newValue}`);
});

// Отслеживаем изменения computed свойства
CSElement.watch([doubledCount.id], (newValue, oldValue) => {
  console.log(`Удвоенное значение: ${oldValue} → ${newValue}`);
});

// Отслеживаем множественные изменения
CSElement.watch([
  [store.id, 'count'],
  [store.id, 'multiplier']
], (values, oldValues) => {
  console.log('Изменились основные данные:', values);
});
```

## 🔍 Live Queries - реактивные запросы

Live Queries автоматически обновляют результаты поиска при изменении данных.

### Создание Live Query

```typescript
// Создаем коллекцию пользователей
const users = CSElement.create('Users');

// Добавляем пользователей
await users.addElement('user1', {
  data: new Map([
    ['name', 'Алексей'],
    ['role', 'admin'],
    ['active', true],
    ['lastLogin', Date.now()]
  ])
});

await users.addElement('user2', {
  data: new Map([
    ['name', 'Мария'],
    ['role', 'user'],
    ['active', true],
    ['lastLogin', Date.now() - 86400000] // вчера
  ])
});

// Создаем Live Query для активных пользователей
const activeUsersQuery = CSElement.createLiveQuery('[active=true]', {
  debounce: 100,
  cache: true
});

// Подписываемся на результаты
activeUsersQuery.onResults(activeUsers => {
  console.log(`Активных пользователей: ${activeUsers.length}`);
  activeUsers.forEach(user => {
    console.log(`- ${user.getData('name')} (${user.getData('role')})`);
  });
});

// Запускаем отслеживание
CSElement.liveQueries.start(activeUsersQuery.id);

// Теперь при изменении пользователей результаты обновятся автоматически!
```

### Продвинутые Live Queries

```typescript
// Live Query с фильтрами и трансформациями
const adminStatsQuery = CSElement.createLiveQuery('[role=admin]')
  .filter(admin => admin.getData('active') === true)
  .transform(admin => ({
    name: admin.getData('name'),
    lastLogin: new Date(admin.getData('lastLogin')).toLocaleDateString(),
    isOnline: Date.now() - admin.getData('lastLogin') < 300000 // 5 минут
  }))
  .sort((a, b) => a.name.localeCompare(b.name))
  .onResults(adminStats => {
    console.log('Статистика администраторов:', adminStats);
  });

// Live Query с агрегацией данных
const userStatsQuery = CSElement.createLiveQuery('*')
  .transform(user => user.getData('role'))
  .onResults(roles => {
    const stats = roles.reduce((acc, role) => {
      acc[role] = (acc[role] || 0) + 1;
      return acc;
    }, {});
    
    console.log('Статистика по ролям:', stats);
  });

CSElement.liveQueries.start(adminStatsQuery.id);
CSElement.liveQueries.start(userStatsQuery.id);
```

## 🎨 Создание реактивных компонентов

### Реактивный счетчик

```typescript
class ReactiveCounter extends CSElement {
  private countQuery: any;
  private doubledQuery: any;

  constructor(initialValue: number = 0) {
    super('ReactiveCounter');
    this.withData('count', initialValue);
    this.setupReactivity();
  }

  private setupReactivity() {
    // Отслеживаем изменения счетчика
    this.countQuery = CSElement.createLiveQuery(`[id=${this.id}]`)
      .transform(element => element.getData('count'))
      .onResults(([count]) => {
        this.emit('count:changed', count);
        this.updateDisplay(count);
      });

    // Computed свойство для удвоенного значения
    this.doubledQuery = CSElement.computed(() => {
      return this.getData('count') * 2;
    });

    CSElement.liveQueries.start(this.countQuery.id);
  }

  private updateDisplay(count: number) {
    console.log(`Счетчик: ${count}, Удвоенное: ${this.doubledQuery.value}`);
  }

  async increment() {
    const current = this.getData('count') || 0;
    await this.setData('count', current + 1);
  }

  async decrement() {
    const current = this.getData('count') || 0;
    await this.setData('count', current - 1);
  }

  async reset() {
    await this.setData('count', 0);
  }

  get count(): number {
    return this.getData('count') || 0;
  }

  get doubled(): number {
    return this.doubledQuery.value;
  }
}

// Использование
const counter = new ReactiveCounter(5);

counter.on('count:changed', (newCount) => {
  console.log(`Событие: счетчик изменился на ${newCount}`);
});

await counter.increment(); // Счетчик: 6, Удвоенное: 12
await counter.increment(); // Счетчик: 7, Удвоенное: 14
await counter.reset();     // Счетчик: 0, Удвоенное: 0
```

### Реактивная корзина покупок

```typescript
class ReactiveShoppingCart extends CSElement {
  private itemsQuery: any;
  private totalQuery: any;
  private itemCountQuery: any;

  constructor() {
    super('ShoppingCart');
    this.setupQueries();
  }

  private setupQueries() {
    // Отслеживаем все товары в корзине
    this.itemsQuery = CSElement.createLiveQuery('[type=cartItem]', {
      root: this,
      debounce: 50
    }).onResults(items => {
      this.emit('items:changed', items);
      this.updateCartDisplay(items);
    });

    // Computed для общей суммы
    this.totalQuery = CSElement.computed(() => {
      const items = this.query('[type=cartItem]');
      return items.reduce((total, item) => {
        const price = item.getData('price') || 0;
        const quantity = item.getData('quantity') || 0;
        return total + (price * quantity);
      }, 0);
    });

    // Computed для количества товаров
    this.itemCountQuery = CSElement.computed(() => {
      const items = this.query('[type=cartItem]');
      return items.reduce((count, item) => {
        return count + (item.getData('quantity') || 0);
      }, 0);
    });

    CSElement.liveQueries.start(this.itemsQuery.id);

    // Отслеживаем изменения общей суммы
    CSElement.watch([this.totalQuery.id], (newTotal) => {
      this.setData('total', newTotal);
      this.emit('total:changed', newTotal);
    });

    // Отслеживаем изменения количества товаров
    CSElement.watch([this.itemCountQuery.id], (newCount) => {
      this.setData('itemCount', newCount);
      this.emit('itemCount:changed', newCount);
    });
  }

  private updateCartDisplay(items: CSElement[]) {
    console.log('\n🛒 Корзина покупок:');
    if (items.length === 0) {
      console.log('Корзина пуста');
      return;
    }

    items.forEach(item => {
      const name = item.getData('name');
      const price = item.getData('price');
      const quantity = item.getData('quantity');
      const subtotal = price * quantity;
      console.log(`  ${name} - ${price}₽ × ${quantity} = ${subtotal}₽`);
    });

    console.log(`\nВсего товаров: ${this.itemCountQuery.value}`);
    console.log(`Общая сумма: ${this.totalQuery.value}₽`);
  }

  async addItem(product: {
    id: string;
    name: string;
    price: number;
    quantity?: number;
  }) {
    const existingItem = this.getElement(product.id);
    
    if (existingItem) {
      // Увеличиваем количество существующего товара
      const currentQuantity = existingItem.getData('quantity') || 0;
      await existingItem.setData('quantity', currentQuantity + (product.quantity || 1));
    } else {
      // Добавляем новый товар
      await this.addElement(product.id, {
        data: new Map([
          ['type', 'cartItem'],
          ['name', product.name],
          ['price', product.price],
          ['quantity', product.quantity || 1]
        ])
      });
    }
  }

  async removeItem(productId: string) {
    return await this.removeElement(productId);
  }

  async updateQuantity(productId: string, quantity: number) {
    const item = this.getElement(productId);
    if (item) {
      if (quantity <= 0) {
        await this.removeItem(productId);
      } else {
        await item.setData('quantity', quantity);
      }
    }
  }

  async clear() {
    const items = this.query('[type=cartItem]');
    for (const item of items) {
      await this.removeElement(item);
    }
  }

  get total(): number {
    return this.totalQuery.value;
  }

  get itemCount(): number {
    return this.itemCountQuery.value;
  }

  getItems(): CSElement[] {
    return this.query('[type=cartItem]');
  }
}

// Использование корзины
const cart = new ReactiveShoppingCart();

// Подписываемся на события
cart.on('total:changed', (newTotal) => {
  console.log(`💰 Общая сумма изменилась: ${newTotal}₽`);
});

cart.on('itemCount:changed', (newCount) => {
  console.log(`📦 Количество товаров: ${newCount}`);
});

// Добавляем товары
await cart.addItem({
  id: 'laptop',
  name: 'Ноутбук',
  price: 50000,
  quantity: 1
});

await cart.addItem({
  id: 'mouse',
  name: 'Мышь',
  price: 2000,
  quantity: 2
});

await cart.addItem({
  id: 'laptop', // Увеличит количество существующего товара
  name: 'Ноутбук',
  price: 50000,
  quantity: 1
});

// Изменяем количество
await cart.updateQuantity('mouse', 1);

// Удаляем товар
await cart.removeItem('mouse');
```

## 🔄 Реактивные вычисления

### Создание цепочек зависимостей

```typescript
// Создаем базовые данные
const gameState = CSElement.create('GameState')
  .withData('level', 1)
  .withData('experience', 0)
  .withData('baseHealth', 100);

// Computed свойства с зависимостями
const levelMultiplier = CSElement.computed(() => {
  const level = gameState.getData('level');
  return 1 + (level - 1) * 0.1; // +10% за уровень
});

const maxHealth = CSElement.computed(() => {
  const baseHealth = gameState.getData('baseHealth');
  return Math.floor(baseHealth * levelMultiplier.value);
});

const experienceToNextLevel = CSElement.computed(() => {
  const level = gameState.getData('level');
  return level * 1000; // 1000 опыта за уровень * текущий уровень
});

const experienceProgress = CSElement.computed(() => {
  const currentExp = gameState.getData('experience');
  const neededExp = experienceToNextLevel.value;
  return Math.min(currentExp / neededExp, 1.0);
});

// Отслеживаем изменения
CSElement.watch([maxHealth.id], (newHealth) => {
  console.log(`💚 Максимальное здоровье: ${newHealth}`);
});

CSElement.watch([experienceProgress.id], (progress) => {
  const percent = Math.round(progress * 100);
  console.log(`⭐ Прогресс до следующего уровня: ${percent}%`);
});

// Функция повышения уровня
async function gainExperience(amount: number) {
  const currentExp = gameState.getData('experience');
  const newExp = currentExp + amount;
  const neededExp = experienceToNextLevel.value;
  
  await gameState.setData('experience', newExp);
  
  if (newExp >= neededExp) {
    const newLevel = gameState.getData('level') + 1;
    await gameState.setData('level', newLevel);
    await gameState.setData('experience', newExp - neededExp);
    console.log(`🎉 Поздравляем! Достигнут ${newLevel} уровень!`);
  }
}

// Симуляция игры
await gainExperience(500);  // ⭐ Прогресс до следующего уровня: 50%
await gainExperience(600);  // 🎉 Поздравляем! Достигнут 2 уровень!
                           // 💚 Максимальное здоровье: 110
                           // ⭐ Прогресс до следующего уровня: 5%
```

### Реактивная аналитика

```typescript
class ReactiveAnalytics extends CSElement {
  private metricsQuery: any;
  private summaryComputed: any;
  private trendsComputed: any;

  constructor() {
    super('Analytics');
    this.setupAnalytics();
  }

  private setupAnalytics() {
    // Отслеживаем все метрики
    this.metricsQuery = CSElement.createLiveQuery('[type=metric]', {
      root: this,
      debounce: 100
    }).onResults(metrics => {
      this.updateAnalytics(metrics);
    });

    // Computed для сводной статистики
    this.summaryComputed = CSElement.computed(() => {
      const metrics = this.query('[type=metric]');
      const summary = {
        totalEvents: metrics.length,
        avgValue: 0,
        minValue: Infinity,
        maxValue: -Infinity,
        categories: new Map()
      };

      if (metrics.length === 0) return summary;

      let totalValue = 0;
      metrics.forEach(metric => {
        const value = metric.getData('value') || 0;
        const category = metric.getData('category') || 'unknown';
        
        totalValue += value;
        summary.minValue = Math.min(summary.minValue, value);
        summary.maxValue = Math.max(summary.maxValue, value);
        
        if (!summary.categories.has(category)) {
          summary.categories.set(category, { count: 0, total: 0 });
        }
        const catStats = summary.categories.get(category);
        catStats.count++;
        catStats.total += value;
      });

      summary.avgValue = totalValue / metrics.length;
      return summary;
    });

    // Computed для трендов (последние 10 метрик)
    this.trendsComputed = CSElement.computed(() => {
      const metrics = this.query('[type=metric]')
        .sort((a, b) => b.getData('timestamp') - a.getData('timestamp'))
        .slice(0, 10);

      if (metrics.length < 2) return { trend: 'insufficient_data' };

      const values = metrics.map(m => m.getData('value')).reverse();
      const trend = this.calculateTrend(values);
      
      return {
        trend,
        recentValues: values,
        change: values.length > 1 ? values[values.length - 1] - values[0] : 0
      };
    });

    CSElement.liveQueries.start(this.metricsQuery.id);

    // Отслеживаем изменения сводки
    CSElement.watch([this.summaryComputed.id], (summary) => {
      this.emit('summary:updated', summary);
    });

    // Отслеживаем изменения трендов
    CSElement.watch([this.trendsComputed.id], (trends) => {
      this.emit('trends:updated', trends);
    });
  }

  private calculateTrend(values: number[]): 'up' | 'down' | 'stable' {
    if (values.length < 2) return 'stable';
    
    const first = values[0];
    const last = values[values.length - 1];
    const change = (last - first) / first;
    
    if (change > 0.05) return 'up';
    if (change < -0.05) return 'down';
    return 'stable';
  }

  private updateAnalytics(metrics: CSElement[]) {
    console.log('\n📊 Обновление аналитики:');
    console.log(`Всего метрик: ${metrics.length}`);
    
    const summary = this.summaryComputed.value;
    if (summary.totalEvents > 0) {
      console.log(`Среднее значение: ${summary.avgValue.toFixed(2)}`);
      console.log(`Диапазон: ${summary.minValue} - ${summary.maxValue}`);
    }

    const trends = this.trendsComputed.value;
    if (trends.trend !== 'insufficient_data') {
      const trendIcon = trends.trend === 'up' ? '📈' : trends.trend === 'down' ? '📉' : '➡️';
      console.log(`Тренд: ${trendIcon} ${trends.trend} (изменение: ${trends.change.toFixed(2)})`);
    }
  }

  async addMetric(category: string, value: number, metadata: any = {}) {
    const metricId = `metric_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    
    await this.addElement(metricId, {
      data: new Map([
        ['type', 'metric'],
        ['category', category],
        ['value', value],
        ['timestamp', Date.now()],
        ['metadata', metadata]
      ])
    });
  }

  getSummary() {
    return this.summaryComputed.value;
  }

  getTrends() {
    return this.trendsComputed.value;
  }

  getMetricsByCategory(category: string): CSElement[] {
    return this.query(`[category=${category}]`);
  }
}

// Использование аналитики
const analytics = new ReactiveAnalytics();

analytics.on('summary:updated', (summary) => {
  console.log('📈 Сводка обновлена:', summary);
});

analytics.on('trends:updated', (trends) => {
  console.log('📊 Тренды обновлены:', trends);
});

// Добавляем метрики
await analytics.addMetric('sales', 1500, { product: 'laptop' });
await analytics.addMetric('sales', 2000, { product: 'phone' });
await analytics.addMetric('visits', 150, { page: 'home' });
await analytics.addMetric('sales', 1800, { product: 'tablet' });
await analytics.addMetric('visits', 200, { page: 'products' });
```

## 🎯 Оптимизация реактивности

### Debouncing и throttling

```typescript
// Создаем элемент с частыми изменениями
const fastChangingElement = CSElement.create('FastChanging')
  .withData('value', 0);

// Live Query с debounce для оптимизации
const debouncedQuery = CSElement.createLiveQuery(`[id=${fastChangingElement.id}]`, {
  debounce: 300 // Обновления не чаще чем раз в 300мс
}).onResults(([element]) => {
  console.log('Debounced update:', element.getData('value'));
});

// Live Query без debounce для сравнения
const immediateQuery = CSElement.createLiveQuery(`[id=${fastChangingElement.id}]`, {
  debounce: 0
}).onResults(([element]) => {
  console.log('Immediate update:', element.getData('value'));
});

CSElement.liveQueries.start(debouncedQuery.id);
CSElement.liveQueries.start(immediateQuery.id);

// Быстрые изменения
for (let i = 1; i <= 10; i++) {
  await fastChangingElement.setData('value', i);
  await new Promise(resolve => setTimeout(resolve, 50));
}
// Immediate update сработает 10 раз
// Debounced update сработает только 1-2 раза
```

### Селективное отслеживание

```typescript
// Отслеживаем только конкретные поля
const selectiveWatcher = CSElement.watch(
  [[fastChangingElement.id, 'importantField']], // Только это поле
  (newValue, oldValue) => {
    console.log('Important field changed:', newValue);
  }
);

// Отслеживаем изменения с условием
const conditionalWatcher = CSElement.watch(
  [[fastChangingElement.id, 'value']],
  (newValue, oldValue) => {
    if (newValue % 10 === 0) { // Только кратные 10
      console.log('Milestone reached:', newValue);
    }
  }
);
```

## 🎉 Полный пример - Реактивная панель мониторинга

```typescript
import { CSElement } from 'cs-element';

class ReactiveDashboard extends CSElement {
  private dataSourcesQuery: any;
  private alertsQuery: any;
  private systemHealthComputed: any;
  private performanceMetricsComputed: any;

  constructor() {
    super('Dashboard');
    this.initializeDataSources();
    this.setupReactiveQueries();
    this.setupComputedMetrics();
    this.setupAlerts();
  }

  private initializeDataSources() {
    // Создаем источники данных
    this.withChild('servers');
    this.withChild('applications');
    this.withChild('databases');
    this.withChild('alerts');
  }

  private setupReactiveQueries() {
    // Отслеживаем все источники данных
    this.dataSourcesQuery = CSElement.createLiveQuery('[type=dataSource]', {
      root: this,
      debounce: 1000
    }).onResults(dataSources => {
      this.updateDashboard(dataSources);
    });

    // Отслеживаем активные алерты
    this.alertsQuery = CSElement.createLiveQuery('[type=alert][status=active]', {
      root: this.getElement('alerts'),
      debounce: 100
    }).onResults(activeAlerts => {
      this.handleAlerts(activeAlerts);
    });

    CSElement.liveQueries.start(this.dataSourcesQuery.id);
    CSElement.liveQueries.start(this.alertsQuery.id);
  }

  private setupComputedMetrics() {
    // Computed для общего здоровья системы
    this.systemHealthComputed = CSElement.computed(() => {
      const servers = this.getElement('servers').query('[type=server]');
      const apps = this.getElement('applications').query('[type=application]');
      const dbs = this.getElement('databases').query('[type=database]');

      const healthyServers = servers.filter(s => s.getData('status') === 'healthy').length;
      const healthyApps = apps.filter(a => a.getData('status') === 'running').length;
      const healthyDbs = dbs.filter(d => d.getData('status') === 'online').length;

      const totalComponents = servers.length + apps.length + dbs.length;
      const healthyComponents = healthyServers + healthyApps + healthyDbs;

      return {
        overallHealth: totalComponents > 0 ? (healthyComponents / totalComponents) * 100 : 100,
        servers: { healthy: healthyServers, total: servers.length },
        applications: { healthy: healthyApps, total: apps.length },
        databases: { healthy: healthyDbs, total: dbs.length }
      };
    });

    // Computed для метрик производительности
    this.performanceMetricsComputed = CSElement.computed(() => {
      const servers = this.getElement('servers').query('[type=server]');
      
      if (servers.length === 0) {
        return { avgCpu: 0, avgMemory: 0, avgDisk: 0 };
      }

      const totalCpu = servers.reduce((sum, s) => sum + (s.getData('cpu') || 0), 0);
      const totalMemory = servers.reduce((sum, s) => sum + (s.getData('memory') || 0), 0);
      const totalDisk = servers.reduce((sum, s) => sum + (s.getData('disk') || 0), 0);

      return {
        avgCpu: totalCpu / servers.length,
        avgMemory: totalMemory / servers.length,
        avgDisk: totalDisk / servers.length
      };
    });

    // Отслеживаем изменения метрик
    CSElement.watch([this.systemHealthComputed.id], (health) => {
      this.emit('health:updated', health);
      this.checkHealthThresholds(health);
    });

    CSElement.watch([this.performanceMetricsComputed.id], (metrics) => {
      this.emit('performance:updated', metrics);
      this.checkPerformanceThresholds(metrics);
    });
  }

  private setupAlerts() {
    // Автоматические алерты на основе метрик
    CSElement.watch([this.performanceMetricsComputed.id], (metrics) => {
      if (metrics.avgCpu > 80) {
        this.createAlert('high_cpu', 'Высокая загрузка CPU', 'critical');
      }
      if (metrics.avgMemory > 90) {
        this.createAlert('high_memory', 'Высокое использование памяти', 'critical');
      }
      if (metrics.avgDisk > 85) {
        this.createAlert('high_disk', 'Мало места на диске', 'warning');
      }
    });
  }

  private updateDashboard(dataSources: CSElement[]) {
    console.log('\n🖥️ Обновление панели мониторинга:');
    console.log(`Источников данных: ${dataSources.length}`);
    
    const health = this.systemHealthComputed.value;
    const performance = this.performanceMetricsComputed.value;

    console.log(`Общее здоровье системы: ${health.overallHealth.toFixed(1)}%`);
    console.log(`Средняя загрузка CPU: ${performance.avgCpu.toFixed(1)}%`);
    console.log(`Средняя загрузка памяти: ${performance.avgMemory.toFixed(1)}%`);
  }

  private handleAlerts(activeAlerts: CSElement[]) {
    if (activeAlerts.length > 0) {
      console.log(`🚨 Активных алертов: ${activeAlerts.length}`);
      activeAlerts.forEach(alert => {
        const severity = alert.getData('severity');
        const message = alert.getData('message');
        const icon = severity === 'critical' ? '🔴' : severity === 'warning' ? '🟡' : '🔵';
        console.log(`${icon} ${message}`);
      });
    }
  }

  private checkHealthThresholds(health: any) {
    if (health.overallHealth < 50) {
      this.createAlert('system_health', 'Критическое состояние системы', 'critical');
    } else if (health.overallHealth < 80) {
      this.createAlert('system_health', 'Проблемы в системе', 'warning');
    }
  }

  private checkPerformanceThresholds(metrics: any) {
    // Логика уже в setupAlerts()
  }

  private async createAlert(id: string, message: string, severity: 'info' | 'warning' | 'critical') {
    const alerts = this.getElement('alerts');
    const existingAlert = alerts.getElement(id);

    if (existingAlert && existingAlert.getData('status') === 'active') {
      return; // Алерт уже существует
    }

    await alerts.addElement(id, {
      data: new Map([
        ['type', 'alert'],
        ['message', message],
        ['severity', severity],
        ['status', 'active'],
        ['timestamp', Date.now()]
      ])
    });
  }

  // Публичные методы для добавления компонентов
  async addServer(id: string, data: {
    name: string;
    cpu: number;
    memory: number;
    disk: number;
    status: 'healthy' | 'warning' | 'critical';
  }) {
    const servers = this.getElement('servers');
    await servers.addElement(id, {
      data: new Map([
        ['type', 'server'],
        ['name', data.name],
        ['cpu', data.cpu],
        ['memory', data.memory],
        ['disk', data.disk],
        ['status', data.status],
        ['lastUpdate', Date.now()]
      ])
    });
  }

  async updateServerMetrics(serverId: string, metrics: {
    cpu?: number;
    memory?: number;
    disk?: number;
    status?: string;
  }) {
    const servers = this.getElement('servers');
    const server = servers.getElement(serverId);
    
    if (server) {
      for (const [key, value] of Object.entries(metrics)) {
        if (value !== undefined) {
          await server.setData(key, value);
        }
      }
      await server.setData('lastUpdate', Date.now());
    }
  }

  async resolveAlert(alertId: string) {
    const alerts = this.getElement('alerts');
    const alert = alerts.getElement(alertId);
    
    if (alert) {
      await alert.setData('status', 'resolved');
      await alert.setData('resolvedAt', Date.now());
    }
  }

  getSystemHealth() {
    return this.systemHealthComputed.value;
  }

  getPerformanceMetrics() {
    return this.performanceMetricsComputed.value;
  }

  getActiveAlerts(): CSElement[] {
    return this.getElement('alerts').query('[status=active]');
  }
}

// Использование панели мониторинга
const dashboard = new ReactiveDashboard();

// Подписываемся на события
dashboard.on('health:updated', (health) => {
  if (health.overallHealth < 80) {
    console.log('⚠️ Внимание: здоровье системы снижено');
  }
});

dashboard.on('performance:updated', (metrics) => {
  if (metrics.avgCpu > 70) {
    console.log('🔥 Высокая загрузка процессора');
  }
});

// Добавляем серверы
await dashboard.addServer('web1', {
  name: 'Web Server 1',
  cpu: 45,
  memory: 60,
  disk: 30,
  status: 'healthy'
});

await dashboard.addServer('db1', {
  name: 'Database Server',
  cpu: 70,
  memory: 80,
  disk: 65,
  status: 'healthy'
});

// Симулируем изменения метрик
setTimeout(async () => {
  await dashboard.updateServerMetrics('web1', { cpu: 85, memory: 75 });
}, 2000);

setTimeout(async () => {
  await dashboard.updateServerMetrics('db1', { cpu: 95, memory: 95 });
}, 4000);

// Через 6 секунд разрешаем алерт
setTimeout(async () => {
  const alerts = dashboard.getActiveAlerts();
  if (alerts.length > 0) {
    await dashboard.resolveAlert(alerts[0].name);
    console.log('✅ Алерт разрешен');
  }
}, 6000);
```

## 🗑️ Auto-Dispose: Автоматическая очистка памяти

CSElement включает продвинутый механизм **auto-dispose** (как в S.js), который автоматически очищает дочерние computed и watchers при пересоздании родительских элементов, предотвращая утечки памяти.

### Базовый принцип

```typescript
const counter = CSElement.ref(0);

// Родительский computed
const parent = CSElement.computed(() => {
  const value = counter.value;
  
  // Дочерние элементы создаются внутри родителя
  const child1 = CSElement.computed(() => value * 2);
  const child2 = CSElement.computed(() => value * 3);
  
  // При пересоздании parent, child1 и child2 автоматически очищаются
  return {
    original: value,
    double: CSElement.getComputedValue(child1.id),
    triple: CSElement.getComputedValue(child2.id)
  };
});

// Первое вычисление создает иерархию
console.log(CSElement.getComputedValue(parent.id));

// Изменение counter пересоздает parent и автоматически очищает детей
counter.value = 5;
console.log(CSElement.getComputedValue(parent.id));
```

### Многоуровневая иерархия

```typescript
const root = CSElement.ref(1);

const deepHierarchy = CSElement.computed(() => {
  const value = root.value;
  
  const level2 = CSElement.computed(() => {
    const level3 = CSElement.computed(() => {
      // Watcher на самом глубоком уровне
      CSElement.watch([root.id], (newVal) => {
        console.log(`Deep watcher: ${newVal}`);
      });
      return value * 4;
    });
    
    return CSElement.getComputedValue(level3.id) * 2;
  });
  
  return CSElement.getComputedValue(level2.id) * 2;
});

// При dispose корневого элемента очищается вся иерархия
CSElement.disposeComputed(deepHierarchy.id);
```

### Области видимости (Scopes)

```typescript
// Создаем область видимости
const scope = CSElement.createScope();

// Выполняем код в контексте области
const result = CSElement.runInScope(scope.id, () => {
  const ref = CSElement.ref(10);
  const computed = CSElement.computed(() => ref.value * 5);
  const watcher = CSElement.watch([ref.id], () => {
    console.log('Scoped watcher');
  });
  
  return CSElement.getComputedValue(computed.id);
});

// Очищаем всю область и все её элементы
CSElement.disposeScope(scope.id);
```

### React-стиль useEffect

```typescript
function useEffect(effect: () => (() => void) | void, deps: any[]) {
  const computed = CSElement.computed(() => {
    // Отслеживаем зависимости
    deps.forEach(dep => {
      if (dep && typeof dep === 'object' && 'value' in dep) {
        dep.value; // Читаем для отслеживания
      }
    });
    
    const cleanup = effect();
    return cleanup;
  });
  
  return () => CSElement.disposeComputed(computed.id);
}

const dependency = CSElement.ref(0);

const cleanup = useEffect(() => {
  console.log('Effect runs');
  
  return () => {
    console.log('Cleanup runs');
  };
}, [dependency]);

// При изменении зависимости effect пересоздается
dependency.value = 1;

// Ручная очистка
cleanup();
```

### Настройка auto-dispose

```typescript
CSElement.configureReactivity({
  autoDispose: true,              // Включить auto-dispose
  maxDisposeDepth: 50,           // Максимальная глубина иерархии
  warnMemoryLeaks: true,         // Предупреждения об утечках
  debug: true                    // Отладочная информация
});
```

### События auto-dispose

```typescript
// Слушаем события очистки
CSElement.onReactivityEvent('computed-disposed', (data) => {
  console.log(`Computed ${data.computedId} disposed`);
  console.log(`Children: ${data.children}`);
});

CSElement.onReactivityEvent('watcher-disposed', (data) => {
  console.log(`Watcher ${data.watcherId} disposed`);
});

CSElement.onReactivityEvent('scope-disposed', (data) => {
  console.log(`Scope ${data.scopeId} disposed`);
});

CSElement.onReactivityEvent('memory-leak-detected', (data) => {
  console.warn(`Potential memory leak:`, data.leakInfo);
});
```

### Ручное управление

```typescript
// Ручная очистка computed
CSElement.disposeComputed(computedId);

// Ручная очистка watcher
CSElement.disposeWatcher(watcherId);

// Проверка состояния
if (CSElement.isDisposed(elementId, 'computed')) {
  console.log('Element was disposed');
}

// Получение детей
const children = CSElement.getChildren(parentId, 'computed');
console.log('Child computed:', children);
```

### Производительность

Auto-dispose оптимизирован для высокой производительности:

```typescript
// Тест с большой иерархией
const bigHierarchy = CSElement.computed(() => {
  const value = ref.value;
  
  // 100 computed + 100 watchers
  for (let i = 0; i < 100; i++) {
    CSElement.computed(() => value + i);
    CSElement.watch([ref.id], () => {});
  }
  
  return value;
});

// Быстрая очистка всей иерархии
console.time('dispose');
CSElement.disposeComputed(bigHierarchy.id);
console.timeEnd('dispose'); // < 10ms
```

## 🎉 Заключение

Реактивность в CSElement предоставляет мощные инструменты для создания отзывчивых приложений:

- **🔄 Live Queries** - автоматическое обновление результатов поиска
- **⚡ Computed свойства** - вычисляемые значения с кэшированием
- **🗑️ Auto-dispose** - автоматическая очистка памяти без утечек
- **👀 Watchers** - отслеживание изменений с гибкой настройкой
- **🎯 Оптимизация** - debouncing, throttling, селективное отслеживание
- **🚨 Реактивные алерты** - автоматическое реагирование на изменения

**Готовы изучить типизированные элементы?** Переходите к [следующему разделу](04-typed-elements.md)! 🚀 