"""
Manual test script for energy calculator.

This script runs basic tests to verify the energy calculator implementation.
"""

from datetime import datetime, timedelta
from app.ml.energy_calculator import (
    calculate_energy_score,
    apply_source_weights,
    adjust_weights_for_degraded_mode,
    apply_temporal_weighting,
    normalize_score,
    calculate_confidence
)


def test_apply_source_weights():
    """Test source weight application."""
    print("\n=== Test: Apply Source Weights ===")

    # Test with all sources
    weighted_score = apply_source_weights(
        twitter_score=50.0,
        reddit_score=40.0,
        rss_score=30.0,
        available_sources=['twitter', 'reddit', 'rss']
    )
    expected = (50.0 * 0.60) + (40.0 * 0.25) + (30.0 * 0.15)
    assert weighted_score == expected, f"Expected {expected}, got {weighted_score}"
    print(f"✓ All sources: {weighted_score} (expected: {expected})")

    # Test with Twitter only
    weighted_score = apply_source_weights(
        twitter_score=50.0,
        reddit_score=0.0,
        rss_score=0.0,
        available_sources=['twitter']
    )
    assert weighted_score == 50.0, f"Expected 50.0, got {weighted_score}"
    print(f"✓ Twitter only: {weighted_score}")


def test_adjust_weights_for_degraded_mode():
    """Test degraded mode weight adjustment."""
    print("\n=== Test: Adjust Weights for Degraded Mode ===")

    original_weights = {
        'twitter': 0.60,
        'reddit': 0.25,
        'rss': 0.15
    }

    # Test with Twitter and Reddit only
    adjusted = adjust_weights_for_degraded_mode(
        original_weights=original_weights,
        available_sources=['twitter', 'reddit']
    )
    total_weight = sum(adjusted.values())
    assert abs(total_weight - 1.0) < 0.001, f"Total weight should be 1.0, got {total_weight}"
    print(f"✓ Twitter+Reddit weights: {adjusted} (total: {total_weight})")

    # Test with only Twitter
    adjusted = adjust_weights_for_degraded_mode(
        original_weights=original_weights,
        available_sources=['twitter']
    )
    total_weight = sum(adjusted.values())
    assert adjusted['twitter'] == 1.0, f"Twitter weight should be 1.0, got {adjusted['twitter']}"
    print(f"✓ Twitter only: {adjusted}")


def test_normalize_score():
    """Test score normalization."""
    print("\n=== Test: Normalize Score ===")

    # Test negative score
    normalized = normalize_score(-10.0)
    assert normalized == 0.0, f"Expected 0.0, got {normalized}"
    print(f"✓ Negative score: -10.0 → {normalized}")

    # Test score above 100
    normalized = normalize_score(150.0)
    assert normalized == 100.0, f"Expected 100.0, got {normalized}"
    print(f"✓ Score above 100: 150.0 → {normalized}")

    # Test score in range
    normalized = normalize_score(50.0)
    assert normalized == 50.0, f"Expected 50.0, got {normalized}"
    print(f"✓ Score in range: 50.0 → {normalized}")


def test_calculate_confidence():
    """Test confidence calculation."""
    print("\n=== Test: Calculate Confidence ===")

    # Test with all sources
    confidence = calculate_confidence(
        available_sources=['twitter', 'reddit', 'rss'],
        total_weight=1.0
    )
    assert confidence > 0.6, f"Confidence should be > 0.6, got {confidence}"
    print(f"✓ All sources: {confidence}")

    # Test with single source (Twitter)
    confidence = calculate_confidence(
        available_sources=['twitter'],
        total_weight=0.6
    )
    assert confidence == 0.6, f"Expected 0.6, got {confidence}"
    print(f"✓ Twitter only: {confidence}")

    # Test with no sources
    confidence = calculate_confidence(
        available_sources=[],
        total_weight=0.0
    )
    assert confidence == 0.0, f"Expected 0.0, got {confidence}"
    print(f"✓ No sources: {confidence}")


def test_apply_temporal_weighting():
    """Test temporal weighting."""
    print("\n=== Test: Apply Temporal Weighting ===")

    base_score = 50.0
    now = datetime.utcnow()

    # Test with recent tweets (within 1 hour)
    recent_tweets = [
        {
            'compound': 0.5,
            'created_at': now - timedelta(minutes=30)
        },
        {
            'compound': 0.6,
            'created_at': now - timedelta(minutes=15)
        }
    ]
    weighted_score = apply_temporal_weighting(
        base_score=base_score,
        tweets_with_timestamps=recent_tweets
    )
    assert 0 <= weighted_score <= 100, f"Score should be between 0 and 100, got {weighted_score}"
    print(f"✓ Recent tweets: {base_score} → {weighted_score}")

    # Test with old tweets (24+ hours)
    old_tweets = [
        {
            'compound': 0.5,
            'created_at': now - timedelta(hours=30)
        },
        {
            'compound': 0.6,
            'created_at': now - timedelta(hours=25)
        }
    ]
    weighted_score = apply_temporal_weighting(
        base_score=base_score,
        tweets_with_timestamps=old_tweets
    )
    assert 0 <= weighted_score <= 100, f"Score should be between 0 and 100, got {weighted_score}"
    print(f"✓ Old tweets: {base_score} → {weighted_score}")


def test_calculate_energy_score_all_sources():
    """Test energy score calculation with all sources."""
    print("\n=== Test: Calculate Energy Score (All Sources) ===")

    twitter_sentiments = [
        {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'},
        {'compound': 0.7, 'positive': 0.7, 'negative': 0.1, 'neutral': 0.2, 'sentiment': 'positive'}
    ]

    reddit_sentiments = [
        {'compound': 0.3, 'positive': 0.4, 'negative': 0.3, 'neutral': 0.3, 'sentiment': 'positive'}
    ]

    rss_sentiments = [
        {'compound': 0.4, 'positive': 0.5, 'negative': 0.2, 'neutral': 0.3, 'sentiment': 'positive'}
    ]

    result = calculate_energy_score(
        match_id=1,
        team_id=1,
        twitter_sentiments=twitter_sentiments,
        reddit_sentiments=reddit_sentiments,
        rss_sentiments=rss_sentiments
    )

    assert 'score' in result, "Result should contain 'score'"
    assert 'confidence' in result, "Result should contain 'confidence'"
    assert 'sources_used' in result, "Result should contain 'sources_used'"
    assert 0 <= result['score'] <= 100, f"Score should be between 0 and 100, got {result['score']}"
    assert len(result['sources_used']) == 3, f"Should use 3 sources, got {len(result['sources_used'])}"
    assert result['confidence'] > 0.6, f"Confidence should be > 0.6, got {result['confidence']}"

    print(f"✓ Score: {result['score']}")
    print(f"✓ Confidence: {result['confidence']}")
    print(f"✓ Sources used: {result['sources_used']}")


def test_calculate_energy_score_degraded_mode():
    """Test energy score calculation in degraded mode."""
    print("\n=== Test: Calculate Energy Score (Degraded Mode) ===")

    twitter_sentiments = [
        {'compound': 0.5, 'positive': 0.6, 'negative': 0.2, 'neutral': 0.2, 'sentiment': 'positive'}
    ]

    result = calculate_energy_score(
        match_id=1,
        team_id=1,
        twitter_sentiments=twitter_sentiments,
        reddit_sentiments=[],
        rss_sentiments=[]
    )

    assert result['score'] >= 0, f"Score should be >= 0, got {result['score']}"
    assert result['confidence'] < 0.6, f"Confidence should be < 0.6 in degraded mode, got {result['confidence']}"
    assert len(result['sources_used']) == 1, f"Should use 1 source, got {len(result['sources_used'])}"
    assert 'twitter' in result['sources_used'], "Should use Twitter"

    print(f"✓ Score: {result['score']}")
    print(f"✓ Confidence: {result['confidence']} (lower in degraded mode)")
    print(f"✓ Sources used: {result['sources_used']}")


def test_calculate_energy_score_no_data():
    """Test energy score calculation with no data."""
    print("\n=== Test: Calculate Energy Score (No Data) ===")

    result = calculate_energy_score(
        match_id=1,
        team_id=1,
        twitter_sentiments=[],
        reddit_sentiments=[],
        rss_sentiments=[]
    )

    assert result['score'] == 0.0, f"Score should be 0.0, got {result['score']}"
    assert result['confidence'] == 0.0, f"Confidence should be 0.0, got {result['confidence']}"
    assert len(result['sources_used']) == 0, f"Should use 0 sources, got {len(result['sources_used'])}"

    print(f"✓ Score: {result['score']}")
    print(f"✓ Confidence: {result['confidence']}")
    print(f"✓ Sources used: {result['sources_used']}")


def main():
    """Run all manual tests."""
    print("=" * 60)
    print("MANUAL TESTS FOR ENERGY CALCULATOR")
    print("=" * 60)

    try:
        test_apply_source_weights()
        test_adjust_weights_for_degraded_mode()
        test_normalize_score()
        test_calculate_confidence()
        test_apply_temporal_weighting()
        test_calculate_energy_score_all_sources()
        test_calculate_energy_score_degraded_mode()
        test_calculate_energy_score_no_data()

        print("\n" + "=" * 60)
        print("✅ ALL TESTS PASSED!")
        print("=" * 60)
        return 0

    except AssertionError as e:
        print(f"\n❌ TEST FAILED: {e}")
        return 1
    except Exception as e:
        print(f"\n❌ UNEXPECTED ERROR: {e}")
        import traceback
        traceback.print_exc()
        return 1


if __name__ == '__main__':
    exit(main())
