"""
Test script to verify reports sync fix
Tests that the reports_sync endpoint now sends actual report data instead of empty JSON
"""

import sys
import os
import json
from unittest.mock import Mock, MagicMock, patch, call
from datetime import datetime

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

from mbetterclient.api_client.client import APIClient, ReportsSyncResponseHandler, APIEndpoint
from mbetterclient.database.manager import DatabaseManager
from mbetterclient.config.manager import ConfigManager
from mbetterclient.config.settings import ApiConfig
from mbetterclient.core.message_bus import MessageBus, MessageType


def test_reports_sync_sends_data():
    """Test that reports_sync endpoint sends actual report data"""
    print("\n=== Test: Reports Sync Sends Actual Data ===")
    
    # Create mock dependencies
    mock_db_manager = Mock()
    mock_config_manager = Mock()
    mock_settings = Mock(spec=ApiConfig)
    mock_settings.rustdesk_id = "test_rustdesk_123"
    mock_settings.user_agent = "MbetterClient/1.0r14"
    mock_settings.verify_ssl = False
    mock_settings.timeout_seconds = 30
    mock_settings.retry_attempts = 3
    mock_settings.retry_delay_seconds = 5
    mock_settings.max_consecutive_failures = 5
    
    # Mock config manager to return API config
    mock_config_manager.get_section_config = Mock(side_effect=lambda section: {
        "api": {
            "fastapi_url": "https://mbetter.nexlab.net",
            "api_token": "test_token_12345",
            "api_interval": 1800
        }
    }.get(section, {}))
    
    # Mock message bus
    mock_message_bus = Mock(spec=MessageBus)
    mock_message_bus.register_component = Mock(return_value=Mock())
    mock_message_bus.subscribe = Mock()
    mock_message_bus.publish = Mock()
    mock_message_bus.get_message = Mock(return_value=None)
    
    # Create API client
    with patch('mbetterclient.api_client.client.create_requests_session_with_ssl_support') as mock_session:
        mock_session.return_value = Mock()
        
        api_client = APIClient(
            message_bus=mock_message_bus,
            db_manager=mock_db_manager,
            config_manager=mock_config_manager,
            settings=mock_settings
        )
        
        # Initialize the client
        api_client.initialize()
        
        # Get reports_sync endpoint
        reports_sync_endpoint = api_client.endpoints.get('reports_sync')
        assert reports_sync_endpoint is not None, "reports_sync endpoint should exist"
        
        print(f"✓ reports_sync endpoint found")
        print(f"✓ Endpoint URL: {reports_sync_endpoint.url}")
        print(f"✓ Endpoint method: {reports_sync_endpoint.method}")
        
        # Mock the reports handler's collect_report_data method
        reports_handler = api_client.response_handlers.get('reports_sync')
        assert reports_handler is not None, "reports_sync handler should exist"
        
        # Create mock report data
        mock_report_data = {
            'sync_id': 'test_sync_001',
            'client_id': 'test_client_123',
            'sync_timestamp': datetime.utcnow().isoformat(),
            'date_range': 'today',
            'start_date': '2026-02-01T00:00:00',
            'end_date': '2026-02-01T23:59:59',
            'bets': [
                {
                    'uuid': 'bet_001',
                    'fixture_id': 'fixture_001',
                    'bet_datetime': '2026-02-01T10:00:00',
                    'paid': True,
                    'paid_out': False,
                    'total_amount': 100.0,
                    'bet_count': 2,
                    'details': []
                }
            ],
            'extraction_stats': [
                {
                    'match_id': 1,
                    'fixture_id': 'fixture_001',
                    'match_datetime': '2026-02-01T10:00:00',
                    'total_bets': 10,
                    'total_amount_collected': 1000.0,
                    'total_redistributed': 950.0,
                    'actual_result': 'WIN1',
                    'extraction_result': 'WIN1',
                    'cap_applied': False,
                    'cap_percentage': None,
                    'under_bets': 5,
                    'under_amount': 500.0,
                    'over_bets': 5,
                    'over_amount': 500.0,
                    'result_breakdown': {}
                }
            ],
            'summary': {
                'total_payin': 100.0,
                'total_payout': 950.0,
                'net_profit': -850.0,
                'total_bets': 2,
                'total_matches': 1
            }
        }
        
        # Patch collect_report_data to return mock data
        with patch.object(reports_handler, 'collect_report_data', return_value=mock_report_data):
            # Mock the session.request method to capture the request data
            mock_response = Mock()
            mock_response.status_code = 200
            mock_response.json.return_value = {
                'success': True,
                'synced_count': 1,
                'message': 'Sync successful'
            }
            mock_response.headers = {'content-type': 'application/json'}
            mock_response.text = json.dumps({'success': True, 'synced_count': 1})
            
            api_client.session.request = Mock(return_value=mock_response)
            
            # Execute the endpoint request
            api_client._execute_endpoint_request(reports_sync_endpoint)
            
            # Verify that session.request was called
            assert api_client.session.request.called, "session.request should have been called"
            
            # Get the call arguments
            call_args = api_client.session.request.call_args
            
            # Verify the request was made with correct parameters
            assert call_args is not None, "session.request should have been called with arguments"
            
            # Check the JSON data sent
            json_data = call_args.kwargs.get('json', {})
            
            print(f"\n✓ Request was made")
            print(f"✓ Request method: {call_args.kwargs.get('method')}")
            print(f"✓ Request URL: {call_args.kwargs.get('url')}")
            
            # Verify that the JSON data is not empty
            assert json_data is not None, "JSON data should not be None"
            assert isinstance(json_data, dict), "JSON data should be a dictionary"
            assert len(json_data) > 0, "JSON data should not be empty"
            
            print(f"✓ JSON data is not empty")
            print(f"✓ JSON data keys: {list(json_data.keys())}")
            
            # Verify that the JSON data contains the expected fields
            assert 'sync_id' in json_data, "JSON data should contain 'sync_id'"
            assert 'client_id' in json_data, "JSON data should contain 'client_id'"
            assert 'bets' in json_data, "JSON data should contain 'bets'"
            assert 'extraction_stats' in json_data, "JSON data should contain 'extraction_stats'"
            
            print(f"✓ JSON data contains expected fields")
            print(f"✓ sync_id: {json_data.get('sync_id')}")
            print(f"✓ client_id: {json_data.get('client_id')}")
            print(f"✓ Number of bets: {len(json_data.get('bets', []))}")
            print(f"✓ Number of extraction stats: {len(json_data.get('extraction_stats', []))}")
            
            # Verify that the data matches the mock data
            assert json_data['sync_id'] == mock_report_data['sync_id'], "sync_id should match"
            assert json_data['client_id'] == mock_report_data['client_id'], "client_id should match"
            assert len(json_data['bets']) == len(mock_report_data['bets']), "Number of bets should match"
            assert len(json_data['extraction_stats']) == len(mock_report_data['extraction_stats']), "Number of extraction stats should match"
            
            print(f"✓ JSON data matches mock report data")
            
            # Verify that collect_report_data was called
            reports_handler.collect_report_data.assert_called_once_with(date_range='today')
            print(f"✓ collect_report_data was called with date_range='today'")
            
            print("\n✅ TEST PASSED: Reports sync now sends actual report data instead of empty JSON")
            return True


def test_reports_sync_empty_data_fallback():
    """Test that reports_sync handles data collection failure gracefully"""
    print("\n=== Test: Reports Sync Handles Data Collection Failure ===")
    
    # Create mock dependencies
    mock_db_manager = Mock()
    mock_config_manager = Mock()
    mock_settings = Mock(spec=ApiConfig)
    mock_settings.rustdesk_id = "test_rustdesk_123"
    mock_settings.user_agent = "MbetterClient/1.0r14"
    mock_settings.verify_ssl = False
    mock_settings.timeout_seconds = 30
    mock_settings.retry_attempts = 3
    mock_settings.retry_delay_seconds = 5
    mock_settings.max_consecutive_failures = 5
    
    # Mock config manager to return API config
    mock_config_manager.get_section_config = Mock(side_effect=lambda section: {
        "api": {
            "fastapi_url": "https://mbetter.nexlab.net",
            "api_token": "test_token_12345",
            "api_interval": 1800
        }
    }.get(section, {}))
    
    # Mock message bus
    mock_message_bus = Mock(spec=MessageBus)
    mock_message_bus.register_component = Mock(return_value=Mock())
    mock_message_bus.subscribe = Mock()
    mock_message_bus.publish = Mock()
    mock_message_bus.get_message = Mock(return_value=None)
    
    # Create API client
    with patch('mbetterclient.api_client.client.create_requests_session_with_ssl_support') as mock_session:
        mock_session.return_value = Mock()
        
        api_client = APIClient(
            message_bus=mock_message_bus,
            db_manager=mock_db_manager,
            config_manager=mock_config_manager,
            settings=mock_settings
        )
        
        # Initialize the client
        api_client.initialize()
        
        # Get reports_sync endpoint
        reports_sync_endpoint = api_client.endpoints.get('reports_sync')
        
        # Get reports handler
        reports_handler = api_client.response_handlers.get('reports_sync')
        
        # Patch collect_report_data to raise an exception
        with patch.object(reports_handler, 'collect_report_data', side_effect=Exception("Database error")):
            # Mock the session.request method
            mock_response = Mock()
            mock_response.status_code = 200
            mock_response.json.return_value = {
                'success': True,
                'synced_count': 0,
                'message': 'Sync successful'
            }
            mock_response.headers = {'content-type': 'application/json'}
            mock_response.text = json.dumps({'success': True, 'synced_count': 0})
            
            api_client.session.request = Mock(return_value=mock_response)
            
            # Execute the endpoint request
            api_client._execute_endpoint_request(reports_sync_endpoint)
            
            # Verify that session.request was called
            assert api_client.session.request.called, "session.request should have been called"
            
            # Get the call arguments
            call_args = api_client.session.request.call_args
            
            # Check the JSON data sent
            json_data = call_args.kwargs.get('json', {})
            
            print(f"✓ Request was made even after data collection failure")
            print(f"✓ JSON data: {json_data}")
            
            # Verify that empty data was sent as fallback
            assert json_data == {}, "Empty JSON should be sent as fallback"
            
            print(f"✓ Empty JSON sent as fallback when data collection fails")
            
            print("\n✅ TEST PASSED: Reports sync handles data collection failure gracefully")
            return True


def run_all_tests():
    """Run all tests"""
    print("=" * 80)
    print("REPORTS SYNC FIX VERIFICATION TEST SUITE")
    print("=" * 80)
    
    tests = [
        test_reports_sync_sends_data,
        test_reports_sync_empty_data_fallback
    ]
    
    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)