"""
Tests for Quantum Readiness Score Calculator
"""

import pytest
from datetime import datetime
from pathlib import Path
import json
import csv
import tempfile

from chronos.core.analyze.readiness_score import (
    QuantumReadinessCalculator,
    ReadinessAssessment,
    GapAnalysis,
    HistoricalSnapshot,
    ReadinessScoreResult,
    ReadinessBenchmark,
)


class TestReadinessCalculator:
    """Test quantum readiness calculator."""
    
    def test_calculator_initialization(self):
        """Test calculator initialization."""
        calc = QuantumReadinessCalculator(verbose=False)
        assert calc is not None
        assert calc.verbose is False
        assert len(calc.historical_snapshots) == 0
    
    def test_calculate_perfect_readiness(self):
        """Test calculation with perfect scores."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            organization_name="Perfect Org",
            crypto_inventory_level=400,
            migration_progress_percent=100,
            detection_capability=150,
            compliance_status=100,
            training_level=100,
        )
        
        assert result.overall_score == 1000
        assert result.overall_percentage == 100.0
        assert result.benchmark_level == "Leading"
        assert result.maturity_level == 4
    
    def test_calculate_developing_readiness(self):
        """Test calculation with minimal scores."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            organization_name="Developing Org",
            crypto_inventory_level=0,
            migration_progress_percent=0,
            detection_capability=0,
            compliance_status=0,
            training_level=0,
        )
        
        assert result.overall_score == 0
        assert result.overall_percentage == 0.0
        assert result.benchmark_level == "Developing"
        assert result.maturity_level == 1
    
    def test_calculate_prepared_readiness(self):
        """Test calculation with mid-range scores."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            organization_name="Prepared Org",
            crypto_inventory_level=200,
            migration_progress_percent=50,
            detection_capability=75,
            compliance_status=50,
            training_level=50,
        )
        
        expected_score = 200 + 125 + 75 + 50 + 50  # 500
        assert result.overall_score == expected_score
        assert result.benchmark_level == "Prepared"  # 500 <= 500 threshold
        assert result.maturity_level == 2
    
    def test_calculate_advanced_readiness(self):
        """Test calculation with high scores."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            organization_name="Advanced Org",
            crypto_inventory_level=350,
            migration_progress_percent=75,
            detection_capability=130,
            compliance_status=85,
            training_level=80,
        )
        
        expected_score = 350 + 187.5 + 130 + 85 + 80  # 832.5
        assert result.overall_score == pytest.approx(expected_score, abs=1)
        assert result.benchmark_level == "Leading"  # 832.5 > 750 threshold
        assert result.maturity_level == 4
    
    def test_input_validation_capping(self):
        """Test that inputs are capped at max values."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=500,  # Over max of 400
            migration_progress_percent=150,  # Over max of 100%
            detection_capability=200,  # Over max of 150
            compliance_status=200,  # Over max of 100
            training_level=200,  # Over max of 100
        )
        
        # Should be capped at 1000 max
        assert result.overall_score == 1000
        assert result.overall_percentage == 100.0
    
    def test_input_validation_flooring(self):
        """Test that inputs are floored at zero."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=-100,
            migration_progress_percent=-50,
            detection_capability=-25,
            compliance_status=-10,
            training_level=-5,
        )
        
        assert result.overall_score == 0
    
    def test_gap_analysis_generation(self):
        """Test gap analysis generation."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=200,
            migration_progress_percent=25,
            detection_capability=75,
            compliance_status=50,
            training_level=0,
        )
        
        # Should have 5 gaps
        assert len(result.gap_analysis) == 5
        
        # Check gap structure
        for gap in result.gap_analysis:
            assert isinstance(gap, GapAnalysis)
            assert gap.factor is not None
            assert gap.gap_size >= 0
            assert gap.gap_percentage >= 0
            assert gap.priority in ['critical', 'high', 'medium', 'low', 'complete']
    
    def test_recommendations_generation(self):
        """Test recommendations generation."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=100,
            migration_progress_percent=10,
            detection_capability=25,
            compliance_status=25,
            training_level=10,
        )
        
        # Should have recommendations
        assert len(result.recommendations) > 0
        assert all(isinstance(rec, str) for rec in result.recommendations)
    
    def test_action_plan_generation(self):
        """Test action plan generation."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=150,
            migration_progress_percent=30,
            detection_capability=50,
            compliance_status=40,
            training_level=30,
        )
        
        # Should have action plan
        assert len(result.action_plan) > 0
        
        # Check action plan structure
        for action, months, priority in result.action_plan:
            assert isinstance(action, str)
            assert isinstance(months, int)
            assert priority in ['critical', 'high', 'medium', 'low']
    
    def test_factor_assessments(self):
        """Test individual factor assessments."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=200,
            migration_progress_percent=50,
            detection_capability=75,
            compliance_status=50,
            training_level=50,
        )
        
        # Check crypto inventory assessment
        assert result.crypto_inventory.name == "Cryptography Inventory"
        assert result.crypto_inventory.score == 200
        assert result.crypto_inventory.max_score == 400
        assert result.crypto_inventory.percentage == pytest.approx(50.0, abs=0.1)
        
        # Check migration assessment
        assert result.migration.name == "PQC Migration"
        assert result.migration.score == pytest.approx(125, abs=1)
        assert result.migration.max_score == 250
        
        # Check detection assessment
        assert result.detection.name == "Threat Detection"
        assert result.detection.score == 75
        assert result.detection.max_score == 150
        
        # Check compliance assessment
        assert result.compliance.name == "Regulatory Compliance"
        assert result.compliance.score == 50
        assert result.compliance.max_score == 100
        
        # Check training assessment
        assert result.training.name == "Training & Awareness"
        assert result.training.score == 50
        assert result.training.max_score == 100
    
    def test_historical_tracking(self):
        """Test historical snapshot tracking."""
        calc = QuantumReadinessCalculator()
        
        # First assessment
        result1 = calc.calculate_readiness_score(
            crypto_inventory_level=100,
            migration_progress_percent=10,
            detection_capability=25,
            compliance_status=25,
            training_level=10,
        )
        
        # Second assessment
        result2 = calc.calculate_readiness_score(
            crypto_inventory_level=200,
            migration_progress_percent=30,
            detection_capability=50,
            compliance_status=50,
            training_level=40,
        )
        
        # Should have 2 snapshots
        assert len(calc.historical_snapshots) == 2
        
        # Check snapshots
        snapshot1 = calc.historical_snapshots[0]
        snapshot2 = calc.historical_snapshots[1]
        
        assert snapshot1.overall_score < snapshot2.overall_score
        assert snapshot2.overall_score > snapshot1.overall_score


class TestReadinessAssessment:
    """Test individual readiness assessments."""
    
    def test_assessment_properties(self):
        """Test assessment object properties."""
        assessment = ReadinessAssessment(
            name="Test Factor",
            score=250,
            max_score=500,
            percentage=50.0,
            status="Advanced",
            maturity_level=3,
            recommendations=["Rec 1", "Rec 2"],
            evidence={"key": "value"},
        )
        
        assert assessment.name == "Test Factor"
        assert assessment.score == 250
        assert assessment.max_score == 500
        assert assessment.percentage == 50.0
        assert assessment.status == "Advanced"
        assert assessment.maturity_level == 3
        assert len(assessment.recommendations) == 2
        assert assessment.evidence["key"] == "value"


class TestGapAnalysis:
    """Test gap analysis."""
    
    def test_gap_analysis_properties(self):
        """Test gap analysis object properties."""
        gap = GapAnalysis(
            factor="Test Factor",
            current_score=250,
            target_score=500,
            gap_size=250,
            gap_percentage=50.0,
            priority="high",
            recommendations=["Close gap"],
            estimated_effort_hours=100.0,
            estimated_completion_months=2.5,
        )
        
        assert gap.factor == "Test Factor"
        assert gap.current_score == 250
        assert gap.target_score == 500
        assert gap.gap_size == 250
        assert gap.gap_percentage == 50.0
        assert gap.priority == "high"
        assert gap.estimated_effort_hours == 100.0
        assert gap.estimated_completion_months == 2.5


class TestHistoricalTracking:
    """Test historical snapshot tracking."""
    
    def test_snapshot_creation(self):
        """Test snapshot creation."""
        snapshot = HistoricalSnapshot(
            timestamp=datetime.now(),
            overall_score=500,
            crypto_inventory=200,
            migration=125,
            detection=50,
            compliance=50,
            training=25,
            benchmark_level="Prepared",
        )
        
        assert snapshot.overall_score == 500
        assert snapshot.crypto_inventory == 200
        assert snapshot.benchmark_level == "Prepared"


class TestExportFunctionality:
    """Test export functionality."""
    
    def test_export_json(self):
        """Test JSON export."""
        calc = QuantumReadinessCalculator()
        result = calc.calculate_readiness_score(
            organization_name="Test Org",
            crypto_inventory_level=300,
            migration_progress_percent=50,
            detection_capability=100,
            compliance_status=75,
            training_level=60,
        )
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            filepath = f.name

        try:
            calc.export_readiness_json(result, filepath)

            # Verify file exists and contains data
            assert Path(filepath).exists()

            with open(filepath) as f:
                data = json.load(f)

            assert data['organization'] == "Test Org"
            # 300 + 125 + 100 + 75 + 60 = 660
            assert data['summary']['overall_score'] == pytest.approx(660, abs=1)
            assert data['summary']['benchmark_level'] == "Advanced"
            assert 'factor_scores' in data
            assert 'gaps' in data
            assert 'recommendations' in data
        
        finally:
            Path(filepath).unlink()
    
    def test_export_csv(self):
        """Test CSV export."""
        calc = QuantumReadinessCalculator()
        result = calc.calculate_readiness_score(
            organization_name="Test Org",
            crypto_inventory_level=300,
            migration_progress_percent=50,
            detection_capability=100,
            compliance_status=75,
            training_level=60,
        )
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
            filepath = f.name
        
        try:
            calc.export_readiness_csv(result, filepath)
            
            # Verify file exists and contains data
            assert Path(filepath).exists()
            
            with open(filepath) as f:
                lines = f.readlines()
            
            assert len(lines) > 0
            assert "Test Org" in ''.join(lines)
        
        finally:
            Path(filepath).unlink()


class TestBenchmarking:
    """Test NIST benchmarking."""
    
    def test_benchmark_developing(self):
        """Test Developing benchmark (0-250 points)."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=100,
            migration_progress_percent=0,
            detection_capability=25,
            compliance_status=25,
            training_level=0,
        )
        
        assert result.benchmark_level == "Developing"
        assert result.maturity_level == 1
    
    def test_benchmark_prepared(self):
        """Test Prepared benchmark (251-500 points)."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=200,
            migration_progress_percent=30,
            detection_capability=50,
            compliance_status=50,
            training_level=25,
        )
        
        assert result.benchmark_level == "Prepared"
        assert result.maturity_level == 2
    
    def test_benchmark_advanced(self):
        """Test Advanced benchmark (501-750 points)."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=300,
            migration_progress_percent=60,
            detection_capability=100,
            compliance_status=75,
            training_level=75,
        )
        
        assert result.benchmark_level == "Advanced"
        assert result.maturity_level == 3
    
    def test_benchmark_leading(self):
        """Test Leading benchmark (751-1000 points)."""
        calc = QuantumReadinessCalculator()
        
        result = calc.calculate_readiness_score(
            crypto_inventory_level=350,
            migration_progress_percent=90,
            detection_capability=140,
            compliance_status=95,
            training_level=90,
        )
        
        assert result.benchmark_level == "Leading"
        assert result.maturity_level == 4


class TestReadinessProgress:
    """Test readiness progress tracking."""
    
    def test_progress_tracking(self):
        """Test tracking readiness progress over time."""
        calc = QuantumReadinessCalculator()
        
        scores = [
            (100, 10, 25, 25, 0),      # 160 total
            (150, 25, 50, 40, 25),     # 290 total
            (200, 50, 75, 60, 50),     # 435 total
            (250, 75, 100, 80, 75),    # 580 total
        ]
        
        for i, (crypto, migration_pct, detect, comp, train) in enumerate(scores):
            result = calc.calculate_readiness_score(
                crypto_inventory_level=crypto,
                migration_progress_percent=migration_pct,
                detection_capability=detect,
                compliance_status=comp,
                training_level=train,
            )
            
            # Each assessment should be higher than previous
            if i > 0:
                assert result.overall_score > calc.historical_snapshots[i-1].overall_score


class TestVisualization:
    """Test visualization generation."""
    
    def test_plot_readiness_overview(self):
        """Test readiness overview visualization."""
        calc = QuantumReadinessCalculator()
        result = calc.calculate_readiness_score(
            organization_name="Test Org",
            crypto_inventory_level=250,
            migration_progress_percent=50,
            detection_capability=75,
            compliance_status=60,
            training_level=50,
        )
        
        fig = calc.plot_readiness_overview(result)
        assert fig is not None
    
    def test_plot_gap_analysis(self):
        """Test gap analysis visualization."""
        calc = QuantumReadinessCalculator()
        result = calc.calculate_readiness_score(
            crypto_inventory_level=150,
            migration_progress_percent=25,
            detection_capability=50,
            compliance_status=40,
            training_level=30,
        )
        
        fig = calc.plot_gap_analysis(result)
        assert fig is not None
    
    def test_plot_progress_trend(self):
        """Test progress trend visualization."""
        calc = QuantumReadinessCalculator()
        
        # Need at least 2 snapshots
        calc.calculate_readiness_score(
            crypto_inventory_level=100,
            migration_progress_percent=10,
            detection_capability=25,
            compliance_status=25,
            training_level=10,
        )
        
        calc.calculate_readiness_score(
            crypto_inventory_level=200,
            migration_progress_percent=30,
            detection_capability=50,
            compliance_status=50,
            training_level=40,
        )
        
        fig = calc.plot_progress_trend()
        assert fig is not None
