"""
Unit tests for visualization and reporting system.

Tests the comprehensive visualization and reporting system to analyze
performance data and generate actionable insights.
"""

import json
import pytest
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch, mock_open
from typing import Dict, List, Any
from datetime import datetime, timezone

import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from src.services.performance import PerformanceMetrics
from src.services.performance_profiling import BenchmarkData


class TestVisualizationReportingSystem:
    """Test the visualization and reporting system."""
    
    @pytest.fixture
    def sample_benchmark_data(self):
        """Create sample benchmark data for testing."""
        return [
            BenchmarkData(
                operation_name="transcription",
                batch_size=1,
                duration_seconds=10.5,
                peak_memory_mb=1024.0,
                throughput_items_per_second=2.5,
                timestamp=datetime.now(timezone.utc)
            ),
            BenchmarkData(
                operation_name="transcription",
                batch_size=2,
                duration_seconds=8.2,
                peak_memory_mb=1536.0,
                throughput_items_per_second=3.1,
                timestamp=datetime.now(timezone.utc)
            ),
            BenchmarkData(
                operation_name="transcription",
                batch_size=4,
                duration_seconds=6.8,
                peak_memory_mb=2048.0,
                throughput_items_per_second=3.7,
                timestamp=datetime.now(timezone.utc)
            )
        ]
    
    @pytest.fixture
    def sample_performance_metrics(self):
        """Create sample performance metrics for testing."""
        return [
            PerformanceMetrics(
                operation="transcription",
                duration_seconds=10.0,
                memory_peak_mb=1024.0,
                cpu_peak_percent=50.0,
                throughput_items_per_second=2.0,
                error_count=0,
                success_count=10,
                total_count=10
            ),
            PerformanceMetrics(
                operation="diarization",
                duration_seconds=15.0,
                memory_peak_mb=1536.0,
                cpu_peak_percent=60.0,
                throughput_items_per_second=1.5,
                error_count=1,
                success_count=9,
                total_count=10
            )
        ]
    
    def test_interactive_chart_creation(self, sample_benchmark_data):
        """Test creation of interactive charts using Plotly."""
        from src.services.visualization_reporting import InteractiveChartGenerator
        
        generator = InteractiveChartGenerator()
        
        # Test throughput chart
        fig = generator.create_throughput_chart(sample_benchmark_data)
        assert isinstance(fig, go.Figure)
        assert len(fig.data) > 0
        assert fig.layout.title.text == "Transcription Throughput by Batch Size"
        
        # Test memory usage chart
        fig = generator.create_memory_chart(sample_benchmark_data)
        assert isinstance(fig, go.Figure)
        assert len(fig.data) > 0
        assert fig.layout.title.text == "Memory Usage by Batch Size"
        
        # Test combined chart
        fig = generator.create_combined_chart(sample_benchmark_data)
        assert isinstance(fig, go.Figure)
        assert len(fig.data) > 0
    
    def test_bottleneck_identification(self, sample_performance_metrics):
        """Test bottleneck identification algorithms."""
        from src.services.visualization_reporting import BottleneckAnalyzer
        
        analyzer = BottleneckAnalyzer()
        
        # Test bottleneck identification
        bottlenecks = analyzer.identify_bottlenecks(sample_performance_metrics)
        
        assert isinstance(bottlenecks, list)
        assert len(bottlenecks) > 0
        
        # Check that bottlenecks have required fields
        for bottleneck in bottlenecks:
            assert 'component' in bottleneck
            assert 'severity' in bottleneck
            assert 'description' in bottleneck
            assert 'recommendation' in bottleneck
    
    def test_report_generation_formats(self, sample_benchmark_data, tmp_path):
        """Test report generation in various formats."""
        from src.services.visualization_reporting import ReportGenerator
        
        generator = ReportGenerator()
        
        # Test HTML report
        html_path = tmp_path / "report.html"
        generator.generate_html_report(sample_benchmark_data, html_path)
        assert html_path.exists()
        
        # Test PDF report
        pdf_path = tmp_path / "report.pdf"
        generator.generate_pdf_report(sample_benchmark_data, pdf_path)
        assert pdf_path.exists()
        
        # Test CSV export
        csv_path = tmp_path / "data.csv"
        generator.export_csv(sample_benchmark_data, csv_path)
        assert csv_path.exists()
        
        # Test JSON export
        json_path = tmp_path / "data.json"
        generator.export_json(sample_benchmark_data, json_path)
        assert json_path.exists()
    
    def test_comparison_views(self, sample_benchmark_data):
        """Test before/after optimization analysis."""
        from src.services.visualization_reporting import ComparisonAnalyzer
        
        analyzer = ComparisonAnalyzer()
        
        # Create "before" and "after" data
        before_data = sample_benchmark_data[:2]  # First two entries
        after_data = sample_benchmark_data[1:]   # Last two entries
        
        # Test comparison analysis
        comparison = analyzer.compare_performance(before_data, after_data)
        
        assert isinstance(comparison, dict)
        assert 'improvements' in comparison
        assert 'regressions' in comparison
        assert 'summary' in comparison
        
        # Test comparison chart
        fig = analyzer.create_comparison_chart(before_data, after_data)
        assert isinstance(fig, go.Figure)
        assert len(fig.data) > 0
    
    def test_trend_analysis(self, sample_benchmark_data):
        """Test trend analysis for performance metrics over time."""
        from src.services.visualization_reporting import TrendAnalyzer
        
        analyzer = TrendAnalyzer()
        
        # Test trend calculation
        trends = analyzer.calculate_trends(sample_benchmark_data)
        
        assert isinstance(trends, dict)
        assert 'throughput_trend' in trends
        assert 'memory_trend' in trends
        assert 'duration_trend' in trends
        
        # Test trend visualization
        fig = analyzer.create_trend_chart(sample_benchmark_data)
        assert isinstance(fig, go.Figure)
        assert len(fig.data) > 0
    
    def test_report_templates(self, sample_benchmark_data, tmp_path):
        """Test different report templates."""
        from src.services.visualization_reporting import ReportTemplateManager
        
        manager = ReportTemplateManager()
        
        # Test executive summary template
        exec_path = tmp_path / "executive_summary.html"
        manager.generate_executive_summary(sample_benchmark_data, exec_path)
        assert exec_path.exists()
        
        # Test detailed technical report template
        tech_path = tmp_path / "technical_report.html"
        manager.generate_technical_report(sample_benchmark_data, tech_path)
        assert tech_path.exists()
        
        # Test custom template
        custom_path = tmp_path / "custom_report.html"
        template_vars = {"title": "Custom Report", "author": "Test User"}
        manager.generate_custom_report(sample_benchmark_data, custom_path, template_vars)
        assert custom_path.exists()
    
    def test_export_functionality(self, sample_benchmark_data, tmp_path):
        """Test export functionality for various formats."""
        from src.services.visualization_reporting import DataExporter
        
        exporter = DataExporter()
        
        # Test CSV export
        csv_path = tmp_path / "export.csv"
        exporter.export_to_csv(sample_benchmark_data, csv_path)
        assert csv_path.exists()
        
        # Verify CSV content
        df = pd.read_csv(csv_path)
        assert len(df) == len(sample_benchmark_data)
        assert 'operation_name' in df.columns
        assert 'batch_size' in df.columns
        
        # Test JSON export
        json_path = tmp_path / "export.json"
        exporter.export_to_json(sample_benchmark_data, json_path)
        assert json_path.exists()
        
        # Verify JSON content
        with open(json_path, 'r') as f:
            data = json.load(f)
        assert isinstance(data, list)
        assert len(data) == len(sample_benchmark_data)
    
    def test_chart_customization(self, sample_benchmark_data):
        """Test chart customization options."""
        from src.services.visualization_reporting import InteractiveChartGenerator
        
        generator = InteractiveChartGenerator()
        
        # Test custom colors
        custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
        fig = generator.create_throughput_chart(
            sample_benchmark_data, 
            colors=custom_colors
        )
        assert isinstance(fig, go.Figure)
        
        # Test custom layout
        custom_layout = {
            'title': 'Custom Title',
            'xaxis_title': 'Custom X Axis',
            'yaxis_title': 'Custom Y Axis'
        }
        fig = generator.create_memory_chart(
            sample_benchmark_data,
            layout=custom_layout
        )
        assert fig.layout.title.text == 'Custom Title'
        assert fig.layout.xaxis.title.text == 'Custom X Axis'
    
    def test_performance_insights(self, sample_performance_metrics):
        """Test performance insights generation."""
        from src.services.visualization_reporting import PerformanceInsightsGenerator
        
        generator = PerformanceInsightsGenerator()
        
        # Test insights generation
        insights = generator.generate_insights(sample_performance_metrics)
        
        assert isinstance(insights, list)
        assert len(insights) > 0
        
        # Check insight structure
        for insight in insights:
            assert 'type' in insight
            assert 'message' in insight
            assert 'severity' in insight
            assert 'actionable' in insight
    
    def test_report_validation(self, sample_benchmark_data, tmp_path):
        """Test report validation and error handling."""
        from src.services.visualization_reporting import ReportValidator
        
        validator = ReportValidator()
        
        # Test valid data
        is_valid = validator.validate_data(sample_benchmark_data)
        assert is_valid
        
        # Test invalid data
        invalid_data = [{"invalid": "data"}]
        is_valid = validator.validate_data(invalid_data)
        assert not is_valid
        
        # Test report file validation
        report_path = tmp_path / "test_report.html"
        with open(report_path, 'w') as f:
            f.write("<html><body>Test Report</body></html>")
        
        is_valid = validator.validate_report_file(report_path)
        assert is_valid


class TestVisualizationReportingIntegration:
    """Integration tests for visualization and reporting system."""
    
    @pytest.mark.asyncio
    async def test_complete_reporting_workflow(self, tmp_path):
        """Test the complete reporting workflow."""
        from src.services.visualization_reporting import (
            ReportGenerator,
            InteractiveChartGenerator,
            BottleneckAnalyzer,
            ComparisonAnalyzer,
            TrendAnalyzer
        )
        
        # Create sample data
        sample_data = [
            BenchmarkData(
                operation_name="transcription",
                batch_size=1,
                duration_seconds=10.0,
                peak_memory_mb=1024.0,
                throughput_items_per_second=2.0,
                timestamp=datetime.now(timezone.utc)
            ),
            BenchmarkData(
                operation_name="transcription",
                batch_size=2,
                duration_seconds=8.0,
                peak_memory_mb=1536.0,
                throughput_items_per_second=2.5,
                timestamp=datetime.now(timezone.utc)
            )
        ]
        
        # Initialize components
        generator = ReportGenerator()
        chart_generator = InteractiveChartGenerator()
        bottleneck_analyzer = BottleneckAnalyzer()
        comparison_analyzer = ComparisonAnalyzer()
        trend_analyzer = TrendAnalyzer()
        
        # Generate charts
        throughput_chart = chart_generator.create_throughput_chart(sample_data)
        memory_chart = chart_generator.create_memory_chart(sample_data)
        combined_chart = chart_generator.create_combined_chart(sample_data)
        
        # Analyze bottlenecks
        bottlenecks = bottleneck_analyzer.identify_bottlenecks(sample_data)
        
        # Generate trends
        trends = trend_analyzer.calculate_trends(sample_data)
        
        # Generate comprehensive report
        report_path = tmp_path / "comprehensive_report.html"
        generator.generate_comprehensive_report(
            sample_data,
            report_path,
            charts=[throughput_chart, memory_chart, combined_chart],
            bottlenecks=bottlenecks,
            trends=trends
        )
        
        # Verify report was generated
        assert report_path.exists()
        
        # Verify report content
        with open(report_path, 'r') as f:
            content = f.read()
            assert "Performance Report" in content
            assert "Bottlenecks" in content
            assert "Trends" in content
    
    def test_multi_format_export(self, tmp_path):
        """Test exporting data in multiple formats."""
        from src.services.visualization_reporting import MultiFormatExporter
        
        exporter = MultiFormatExporter()
        
        # Create sample data
        sample_data = [
            BenchmarkData(
                operation_name="test",
                batch_size=1,
                duration_seconds=5.0,
                peak_memory_mb=512.0,
                throughput_items_per_second=1.0,
                timestamp=datetime.now(timezone.utc)
            )
        ]
        
        # Export in multiple formats
        export_paths = exporter.export_all_formats(sample_data, tmp_path)
        
        # Verify all formats were created
        assert 'html' in export_paths
        assert 'pdf' in export_paths
        assert 'csv' in export_paths
        assert 'json' in export_paths
        
        # Verify files exist
        for format_type, path in export_paths.items():
            assert Path(path).exists()
    
    def test_report_scheduling(self):
        """Test automated report scheduling."""
        from src.services.visualization_reporting import ReportScheduler
        
        scheduler = ReportScheduler()
        
        # Test schedule creation
        schedule = scheduler.create_schedule(
            frequency="daily",
            time="09:00",
            report_type="executive_summary"
        )
        
        assert schedule['frequency'] == "daily"
        assert schedule['time'] == "09:00"
        assert schedule['report_type'] == "executive_summary"
        
        # Test schedule validation
        is_valid = scheduler.validate_schedule(schedule)
        assert is_valid
        
        # Test invalid schedule
        invalid_schedule = {
            'frequency': "invalid",
            'time': "25:00",
            'report_type': "unknown"
        }
        is_valid = scheduler.validate_schedule(invalid_schedule)
        assert not is_valid
