"""
Test script for Reports Synchronization functionality - Database-based implementation
Tests the ReportsSyncResponseHandler with database queue, offline support and incremental sync
"""

import sys
import os
import json
import tempfile
import shutil
from pathlib import Path
from datetime import datetime, timedelta
from unittest.mock import Mock, MagicMock, patch, call

# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from mbetterclient.api_client.client import ReportsSyncResponseHandler, APIEndpoint
from mbetterclient.database.manager import DatabaseManager
from mbetterclient.config.manager import ConfigManager
from mbetterclient.config.settings import ApiConfig


def test_reports_sync_handler_initialization():
    """Test 1: ReportsSyncResponseHandler initialization"""
    print("\n=== Test 1: ReportsSyncResponseHandler Initialization ===")
    
    # Create temporary directory for testing
    with tempfile.TemporaryDirectory() as temp_dir:
        # Mock dependencies
        mock_db_manager = Mock()
        mock_api_client = Mock()
        mock_message_bus = Mock()
        
        # Create handler
        handler = ReportsSyncResponseHandler(
            db_manager=mock_db_manager,
            user_data_dir=temp_dir,
            api_client=mock_api_client,
            message_bus=mock_message_bus
        )
        
        # Verify initialization
        assert handler.max_queue_size == 1000, "Max queue size should be 1000"
        assert handler.max_retries == 5, "Max retries should be 5"
        assert handler.retry_backoff_base == 60, "Retry backoff base should be 60"
        
        print("✓ Handler initialized successfully")
        print(f"✓ Max queue size: {handler.max_queue_size}")
        print(f"✓ Max retries: {handler.max_retries}")
        print(f"✓ Retry backoff base: {handler.retry_backoff_base}s")


def test_sync_id_generation():
    """Test 2: Sync ID generation"""
    print("\n=== Test 2: Sync ID Generation ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        handler = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Generate multiple sync IDs
        sync_ids = [handler._generate_sync_id() for _ in range(5)]
        
        # Verify format
        for sync_id in sync_ids:
            assert sync_id.startswith("sync_"), f"Sync ID should start with 'sync_': {sync_id}"
            assert len(sync_id) > 20, f"Sync ID should be long enough: {sync_id}"
        
        # Verify uniqueness
        assert len(set(sync_ids)) == 5, "All sync IDs should be unique"
        
        print("✓ Sync IDs generated successfully")
        print(f"✓ Sample sync ID: {sync_ids[0]}")
        print(f"✓ All sync IDs are unique")


def test_client_id_generation():
    """Test 3: Client ID generation"""
    print("\n=== Test 3: Client ID Generation ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        # Test with rustdesk_id
        mock_api_client_with_id = Mock()
        mock_settings = Mock()
        mock_settings.rustdesk_id = "test_rustdesk_123"
        mock_api_client_with_id.settings = mock_settings
        
        handler_with_id = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=mock_api_client_with_id,
            message_bus=Mock()
        )
        
        client_id_with_rustdesk = handler_with_id._get_client_id()
        assert client_id_with_rustdesk == "test_rustdesk_123", \
            f"Client ID should use rustdesk_id when available: {client_id_with_rustdesk}"
        
        print("✓ Client ID generated from rustdesk_id")
        print(f"✓ Client ID: {client_id_with_rustdesk}")
        
        # Test without rustdesk_id
        mock_api_client_without_id = Mock()
        mock_settings_no_id = Mock()
        mock_settings_no_id.rustdesk_id = None
        mock_api_client_without_id.settings = mock_settings_no_id
        
        handler_without_id = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=mock_api_client_without_id,
            message_bus=Mock()
        )
        
        client_id_without_rustdesk = handler_without_id._get_client_id()
        assert len(client_id_without_rustdesk) == 16, \
            f"Client ID should be 16 chars without rustdesk_id: {client_id_without_rustdesk}"
        
        print("✓ Client ID generated from machine ID (fallback)")
        print(f"✓ Client ID: {client_id_without_rustdesk}")


def test_queue_status():
    """Test 4: Sync queue status from database"""
    print("\n=== Test 4: Sync Queue Status ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        # Create a proper mock that returns 0 for count queries
        mock_session = Mock()
        mock_query = Mock()
        mock_filter = Mock()
        mock_filter.count.return_value = 0
        mock_query.filter_by.return_value = mock_filter
        mock_query.filter.return_value = mock_filter
        mock_session.query.return_value = mock_query
        
        mock_db = Mock()
        mock_db.get_session.return_value = mock_session
        
        handler = ReportsSyncResponseHandler(
            db_manager=mock_db,
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Test queue status
        status = handler.get_queue_status()
        assert status['pending'] == 0, "No pending items initially"
        assert status['completed'] == 0, "No completed items initially"
        assert status['failed'] == 0, "No failed items initially"
        assert 'max_queue_size' in status, "Status should include max_queue_size"
        
        print("✓ Queue status retrieved successfully")
        print(f"✓ Initial queue status: {status}")


def test_backoff_calculation():
    """Test 5: Exponential backoff calculation"""
    print("\n=== Test 5: Exponential Backoff Calculation ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        handler = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Test backoff times for different retry counts
        base = handler.retry_backoff_base
        expected_backoffs = [
            base * (2 ** 0),  # 60s
            base * (2 ** 1),  # 120s
            base * (2 ** 2),  # 240s
            base * (2 ** 3),  # 480s
            base * (2 ** 4),  # 960s
        ]
        
        print("✓ Backoff times calculated:")
        for i, expected in enumerate(expected_backoffs):
            actual = handler._calculate_backoff_time(i)
            assert actual == expected, f"Backoff calculation incorrect for retry {i}"
            print(f"  Retry {i}: {actual}s (expected: {expected}s)")


def test_response_handling():
    """Test 6: Response handling"""
    print("\n=== Test 6: Response Handling ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        handler = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Mock endpoint
        mock_endpoint = Mock()
        mock_endpoint.name = "reports_sync"
        
        # Test success response
        mock_response = Mock()
        mock_response.json.return_value = {
            'success': True,
            'synced_count': 10,
            'message': 'Sync successful'
        }
        
        result = handler.handle_response(mock_endpoint, mock_response)
        
        assert result['sync_status'] == 'success', "Sync status should be success"
        assert result['synced_items'] == 10, "Synced items count should match"
        assert result['failed_items'] == 0, "Failed items should be 0"
        
        print("✓ Success response handled correctly")
        print(f"✓ Result: {result}")
        
        # Test error response
        mock_error_response = Mock()
        mock_error_response.json.return_value = {
            'success': False,
            'error': 'Invalid data'
        }
        
        error_result = handler.handle_response(mock_endpoint, mock_error_response)
        
        assert error_result['sync_status'] == 'failed', "Sync status should be failed"
        assert 'Invalid data' in error_result['errors'], "Error should be in errors list"
        
        print("✓ Error response handled correctly")
        print(f"✓ Error result: {error_result}")


def test_error_handling():
    """Test 7: Error handling"""
    print("\n=== Test 7: Error Handling ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        handler = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Mock endpoint
        mock_endpoint = Mock()
        mock_endpoint.name = "reports_sync"
        
        # Test error handling
        test_error = Exception("Connection timeout")
        error_result = handler.handle_error(mock_endpoint, test_error)
        
        assert error_result['sync_status'] == 'error', "Sync status should be error"
        assert 'Connection timeout' in error_result['error'], "Error message should be present"
        
        print("✓ Error handled correctly")
        print(f"✓ Error result: {error_result}")


def test_calculation_of_summary():
    """Test 8: Summary calculation"""
    print("\n=== Test 8: Summary Calculation ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        handler = ReportsSyncResponseHandler(
            db_manager=Mock(),
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        # Mock bets
        mock_bet1 = Mock()
        mock_bet1.paid = True
        mock_bet1.paid_out = False
        
        # Mock bet details
        mock_detail1 = Mock()
        mock_detail1.amount = 100.0
        mock_detail1.result = 'win'
        
        mock_detail2 = Mock()
        mock_detail2.amount = 50.0
        mock_detail2.result = 'pending'
        
        mock_bet1.bet_details = [mock_detail1, mock_detail2]
        
        mock_bet2 = Mock()
        mock_bet2.paid = True
        mock_bet2.paid_out = True
        
        mock_detail3 = Mock()
        mock_detail3.amount = 75.0
        mock_detail3.result = 'win'
        
        mock_bet2.bet_details = [mock_detail3]
        
        # Mock extraction stats
        mock_stat1 = Mock()
        mock_stat1.total_redistributed = 90.0
        
        mock_stat2 = Mock()
        mock_stat2.total_redistributed = 60.0
        
        mock_stats = [mock_stat1, mock_stat2]
        
        # Calculate summary
        summary = handler._calculate_summary([mock_bet1, mock_bet2], mock_stats)
        
        assert summary['total_payin'] == 225.0, f"Total payin should be 225.0, got {summary['total_payin']}"
        assert summary['total_payout'] == 150.0, f"Total payout should be 150.0, got {summary['total_payout']}"
        assert summary['net_profit'] == 75.0, f"Net profit should be 75.0, got {summary['net_profit']}"
        assert summary['total_bets'] == 3, f"Total bets should be 3, got {summary['total_bets']}"
        assert summary['total_matches'] == 2, f"Total matches should be 2, got {summary['total_matches']}"
        
        print("✓ Summary calculated correctly")
        print(f"✓ Summary: {summary}")


def test_incremental_sync_logic():
    """Test 9: Incremental sync logic"""
    print("\n=== Test 9: Incremental Sync Logic ===")
    
    with tempfile.TemporaryDirectory() as temp_dir:
        mock_db = Mock()
        mock_session = Mock()
        mock_db.get_session.return_value = mock_session
        
        handler = ReportsSyncResponseHandler(
            db_manager=mock_db,
            user_data_dir=temp_dir,
            api_client=Mock(),
            message_bus=Mock()
        )
        
        print("✓ Handler initialized for incremental sync test")
        print("✓ Incremental sync will use last sync time from ReportsSyncTrackingModel")
        print("✓ Only new/updated records since last sync will be collected")


def run_all_tests():
    """Run all tests"""
    print("=" * 80)
    print("REPORTS SYNCHRONIZATION TEST SUITE - DATABASE-BASED")
    print("=" * 80)
    
    tests = [
        test_reports_sync_handler_initialization,
        test_sync_id_generation,
        test_client_id_generation,
        test_queue_status,
        test_backoff_calculation,
        test_response_handling,
        test_error_handling,
        test_calculation_of_summary,
        test_incremental_sync_logic
    ]
    
    passed = 0
    failed = 0
    
    for test_func in tests:
        try:
            test_func()
            passed += 1
        except AssertionError as e:
            print(f"\n✗ Test failed: {e}")
            failed += 1
        except Exception as e:
            print(f"\n✗ Test error: {e}")
            import traceback
            traceback.print_exc()
            failed += 1
    
    print("\n" + "=" * 80)
    print("TEST SUMMARY")
    print("=" * 80)
    print(f"Total tests: {len(tests)}")
    print(f"Passed: {passed}")
    print(f"Failed: {failed}")
    print(f"Success rate: {(passed/len(tests)*100):.1f}%")
    print("=" * 80)
    
    return failed == 0


if __name__ == "__main__":
    success = run_all_tests()
    sys.exit(0 if success else 1)