<template>
  <div class="heavy-component">
    <h2>Heavy Data Processing Component</h2>
    
    <!-- Data processing controls -->
    <div class="controls">
      <button @click="processData" :disabled="isProcessing">
        {{ isProcessing ? 'Processing...' : 'Process Data' }}
      </button>
      <button @click="clearResults" :disabled="isProcessing">
        Clear Results
      </button>
    </div>
    
    <!-- Processing status -->
    <div v-if="isProcessing" class="processing-status">
      <div class="progress-bar">
        <div class="progress-fill" :style="{ width: progress + '%' }"></div>
      </div>
      <p>Processing {{ processedCount }} of {{ totalItems }} items...</p>
    </div>
    
    <!-- Results display -->
    <div v-if="processedData.length > 0" class="results">
      <h3>Processed Results ({{ processedData.length }} items)</h3>
      
      <!-- Filter controls -->
      <div class="filters">
        <input 
          v-model="searchTerm" 
          placeholder="Search items..."
          class="search-input"
        />
        <select v-model="sortBy" class="sort-select">
          <option value="name">Sort by Name</option>
          <option value="id">Sort by ID</option>
          <option value="processed">Sort by Processed Date</option>
        </select>
      </div>
      
      <!-- Results list -->
      <div class="results-list">
        <div 
          v-for="item in filteredAndSortedData" 
          :key="item.id"
          class="result-item"
        >
          <div class="item-header">
            <span class="item-name">{{ item.name }}</span>
            <span class="item-id">#{{ item.id }}</span>
          </div>
          <div class="item-details">
            <span class="processed-date">
              Processed: {{ formatDate(item.processedAt) }}
            </span>
            <span class="processing-time">
              Time: {{ item.processingTime }}ms
            </span>
          </div>
        </div>
      </div>
      
      <!-- Pagination -->
      <div v-if="totalPages > 1" class="pagination">
        <button 
          @click="previousPage" 
          :disabled="currentPage === 1"
          class="page-btn"
        >
          Previous
        </button>
        <span class="page-info">
          Page {{ currentPage }} of {{ totalPages }}
        </span>
        <button 
          @click="nextPage" 
          :disabled="currentPage === totalPages"
          class="page-btn"
        >
          Next
        </button>
      </div>
    </div>
    
    <!-- Performance metrics -->
    <div v-if="performanceMetrics" class="performance-metrics">
      <h4>Performance Metrics</h4>
      <div class="metrics-grid">
        <div class="metric">
          <span class="metric-label">Total Processing Time:</span>
          <span class="metric-value">{{ performanceMetrics.totalTime }}ms</span>
        </div>
        <div class="metric">
          <span class="metric-label">Average per Item:</span>
          <span class="metric-value">{{ performanceMetrics.averageTime }}ms</span>
        </div>
        <div class="metric">
          <span class="metric-label">Memory Usage:</span>
          <span class="metric-value">{{ performanceMetrics.memoryUsage }}MB</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Emit } from 'vue-facing-decorator';

interface ProcessedItem {
  id: number;
  name: string;
  processedAt: Date;
  processingTime: number;
  result: any;
}

interface PerformanceMetrics {
  totalTime: number;
  averageTime: number;
  memoryUsage: number;
}

/**
 * Heavy Component for Data Processing
 * 
 * Demonstrates a component that performs intensive data processing
 * and would benefit from lazy loading to avoid blocking the main thread.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */
@Component({
  name: 'HeavyComponent'
})
export default class HeavyComponent extends Vue {
  @Prop({ required: true }) readonly data!: {
    items: Array<{ id: number; name: string }>;
    filters: Record<string, any>;
    sortBy: string;
  };
  
  // Component state
  isProcessing = false;
  processedData: ProcessedItem[] = [];
  progress = 0;
  processedCount = 0;
  totalItems = 0;
  
  // UI state
  searchTerm = '';
  sortBy = 'name';
  currentPage = 1;
  itemsPerPage = 50;
  
  // Performance tracking
  performanceMetrics: PerformanceMetrics | null = null;
  startTime = 0;
  
  // Computed properties
  get filteredAndSortedData(): ProcessedItem[] {
    let filtered = this.processedData;
    
    // Apply search filter
    if (this.searchTerm) {
      filtered = filtered.filter(item => 
        item.name.toLowerCase().includes(this.searchTerm.toLowerCase())
      );
    }
    
    // Apply sorting
    filtered.sort((a, b) => {
      switch (this.sortBy) {
        case 'name':
          return a.name.localeCompare(b.name);
        case 'id':
          return a.id - b.id;
        case 'processed':
          return b.processedAt.getTime() - a.processedAt.getTime();
        default:
          return 0;
      }
    });
    
    return filtered;
  }
  
  get paginatedData(): ProcessedItem[] {
    const start = (this.currentPage - 1) * this.itemsPerPage;
    const end = start + this.itemsPerPage;
    return this.filteredAndSortedData.slice(start, end);
  }
  
  get totalPages(): number {
    return Math.ceil(this.filteredAndSortedData.length / this.itemsPerPage);
  }
  
  // Lifecycle hooks
  mounted(): void {
    console.log('[HeavyComponent] Component mounted with', this.data.items.length, 'items');
    this.totalItems = this.data.items.length;
  }
  
  // Methods
  async processData(): Promise<void> {
    if (this.isProcessing) return;
    
    this.isProcessing = true;
    this.progress = 0;
    this.processedCount = 0;
    this.processedData = [];
    this.startTime = performance.now();
    
    console.log('[HeavyComponent] Starting data processing...');
    
    try {
      // Process items in batches to avoid blocking the UI
      const batchSize = 10;
      const items = this.data.items;
      
      for (let i = 0; i < items.length; i += batchSize) {
        const batch = items.slice(i, i + batchSize);
        
        // Process batch
        await this.processBatch(batch);
        
        // Update progress
        this.processedCount = Math.min(i + batchSize, items.length);
        this.progress = (this.processedCount / items.length) * 100;
        
        // Allow UI to update
        await this.$nextTick();
        
        // Small delay to prevent overwhelming the UI
        await new Promise(resolve => setTimeout(resolve, 10));
      }
      
      // Calculate performance metrics
      this.calculatePerformanceMetrics();
      
      // Emit completion event
      this.$emit('data-processed', {
        totalItems: this.processedData.length,
        processingTime: performance.now() - this.startTime,
        metrics: this.performanceMetrics
      });
      
      console.log('[HeavyComponent] Data processing completed');
      
    } catch (error) {
      console.error('[HeavyComponent] Processing error:', error);
      this.$emit('processing-error', error);
    } finally {
      this.isProcessing = false;
    }
  }
  
  private async processBatch(batch: Array<{ id: number; name: string }>): Promise<void> {
    const processedBatch = await Promise.all(
      batch.map(async (item) => {
        const itemStartTime = performance.now();
        
        // Simulate heavy processing
        await this.simulateHeavyProcessing(item);
        
        const processingTime = performance.now() - itemStartTime;
        
        return {
          id: item.id,
          name: item.name,
          processedAt: new Date(),
          processingTime: Math.round(processingTime),
          result: this.generateResult(item)
        };
      })
    );
    
    this.processedData.push(...processedBatch);
  }
  
  private async simulateHeavyProcessing(item: { id: number; name: string }): Promise<void> {
    // Simulate CPU-intensive work
    const complexity = item.name.length * item.id;
    const iterations = Math.min(complexity, 1000); // Cap at 1000 iterations
    
    for (let i = 0; i < iterations; i++) {
      // Simulate work
      Math.sqrt(i) * Math.random();
    }
    
    // Simulate async work
    await new Promise(resolve => setTimeout(resolve, Math.random() * 10));
  }
  
  private generateResult(item: { id: number; name: string }): any {
    return {
      hash: this.generateHash(item.name + item.id),
      category: this.categorizeItem(item),
      score: Math.random() * 100,
      tags: this.generateTags(item)
    };
  }
  
  private generateHash(input: string): string {
    let hash = 0;
    for (let i = 0; i < input.length; i++) {
      const char = input.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // Convert to 32-bit integer
    }
    return hash.toString(16);
  }
  
  private categorizeItem(item: { id: number; name: string }): string {
    const categories = ['A', 'B', 'C', 'D', 'E'];
    return categories[item.id % categories.length];
  }
  
  private generateTags(item: { id: number; name: string }): string[] {
    const tags = ['important', 'urgent', 'review', 'archive', 'featured'];
    return tags.filter((_, index) => (item.id + index) % 3 === 0);
  }
  
  private calculatePerformanceMetrics(): void {
    const totalTime = performance.now() - this.startTime;
    const averageTime = totalTime / this.processedData.length;
    
    // Simulate memory usage calculation
    const memoryUsage = this.processedData.length * 0.1; // 0.1MB per item
    
    this.performanceMetrics = {
      totalTime: Math.round(totalTime),
      averageTime: Math.round(averageTime),
      memoryUsage: Math.round(memoryUsage * 100) / 100
    };
  }
  
  clearResults(): void {
    this.processedData = [];
    this.performanceMetrics = null;
    this.searchTerm = '';
    this.currentPage = 1;
    console.log('[HeavyComponent] Results cleared');
  }
  
  previousPage(): void {
    if (this.currentPage > 1) {
      this.currentPage--;
    }
  }
  
  nextPage(): void {
    if (this.currentPage < this.totalPages) {
      this.currentPage++;
    }
  }
  
  formatDate(date: Date): string {
    return date.toLocaleString();
  }
  
  // Event emitters
  @Emit('data-processed')
  emitDataProcessed(data: any): any {
    return data;
  }
  
  @Emit('processing-error')
  emitProcessingError(error: Error): Error {
    return error;
  }
}
</script>

<style scoped>
.heavy-component {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background: #f9f9f9;
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.controls button {
  padding: 8px 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
  transition: background-color 0.2s;
}

.controls button:hover:not(:disabled) {
  background: #e9ecef;
}

.controls button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.processing-status {
  margin-bottom: 20px;
}

.progress-bar {
  width: 100%;
  height: 20px;
  background: #e9ecef;
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 10px;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #007bff, #0056b3);
  transition: width 0.3s ease;
}

.results {
  margin-top: 20px;
}

.filters {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.search-input,
.sort-select {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.search-input {
  flex: 1;
}

.results-list {
  max-height: 400px;
  overflow-y: auto;
  border: 1px solid #ddd;
  border-radius: 4px;
  background: #fff;
}

.result-item {
  padding: 12px;
  border-bottom: 1px solid #eee;
}

.result-item:last-child {
  border-bottom: none;
}

.item-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
}

.item-name {
  font-weight: bold;
}

.item-id {
  color: #666;
  font-size: 0.9em;
}

.item-details {
  display: flex;
  gap: 20px;
  font-size: 0.85em;
  color: #666;
}

.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 15px;
  margin-top: 20px;
}

.page-btn {
  padding: 6px 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
}

.page-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.page-info {
  font-size: 0.9em;
  color: #666;
}

.performance-metrics {
  margin-top: 20px;
  padding: 15px;
  background: #e8f4fd;
  border-radius: 4px;
}

.metrics-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 15px;
  margin-top: 10px;
}

.metric {
  display: flex;
  justify-content: space-between;
  padding: 8px;
  background: #fff;
  border-radius: 4px;
}

.metric-label {
  font-weight: bold;
  color: #333;
}

.metric-value {
  color: #007bff;
  font-weight: bold;
}
</style> 