#!/usr/bin/env python3
"""
Comprehensive API Data Integrity Test Suite

Compares data between localhost PostgreSQL API and production SQLite API
for all routers except battingstats, custom_commands, fieldingstats, pitchingstats.

Usage:
    python comprehensive_api_integrity_tests.py
    python comprehensive_api_integrity_tests.py --verbose
    python comprehensive_api_integrity_tests.py --router teams
"""

import requests
import json
import sys
import argparse
from typing import Dict, List, Any, Tuple, Optional
from dataclasses import dataclass
from datetime import datetime
import logging

# API Configuration
LOCALHOST_API = "https://api.sba.manticorum.com/v3"
PRODUCTION_API = "https://sba.manticorum.com/api/v3"

# Test Configuration
TEST_SEASON = 10
SAMPLE_PLAYER_IDS = [9916, 9958, 9525, 9349, 9892]
SAMPLE_TEAM_IDS = [404, 428, 443, 422, 425]
SAMPLE_GAME_IDS = [1571, 1458, 1710]
SAMPLE_MANAGER_IDS = [1, 2, 3, 4, 5]

@dataclass
class TestResult:
    """Container for test results"""
    test_name: str
    passed: bool
    localhost_data: Any
    production_data: Any
    error_message: str = ""
    details: Dict[str, Any] = None

class ComprehensiveAPITester:
    """Comprehensive test suite for all API routers"""
    
    def __init__(self, verbose: bool = False):
        self.verbose = verbose
        self.results: List[TestResult] = []
        self.setup_logging()
    
    def setup_logging(self):
        """Setup logging configuration"""
        level = logging.DEBUG if self.verbose else logging.INFO
        log_filename = f'logs/comprehensive_api_test_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'
        logging.basicConfig(
            level=level,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_filename),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
    
    def make_request(self, base_url: str, endpoint: str, params: Dict = None) -> Tuple[bool, Any]:
        """Make API request and return success status and data"""
        try:
            url = f"{base_url}{endpoint}"
            response = requests.get(url, params=params, timeout=30)
            response.raise_for_status()
            return True, response.json()
        except requests.exceptions.RequestException as e:
            self.logger.debug(f"Request failed for {url}: {e}")
            return False, str(e)
    
    def compare_basic_data(self, endpoint: str, params: Dict = None, fields_to_compare: List[str] = None) -> TestResult:
        """Generic comparison for basic endpoint data"""
        test_name = f"{endpoint}: {params or 'no params'}"
        
        if fields_to_compare is None:
            fields_to_compare = ['count']
        
        localhost_success, localhost_data = self.make_request(LOCALHOST_API, endpoint, params)
        production_success, production_data = self.make_request(PRODUCTION_API, endpoint, params)
        
        if not localhost_success or not production_success:
            return TestResult(
                test_name=test_name,
                passed=False,
                localhost_data=localhost_data if localhost_success else None,
                production_data=production_data if production_success else None,
                error_message="API request failed"
            )
        
        # Compare specified fields
        differences = {}
        for field in fields_to_compare:
            localhost_val = localhost_data.get(field)
            production_val = production_data.get(field)
            
            if localhost_val != production_val:
                differences[field] = {
                    'localhost': localhost_val,
                    'production': production_val
                }
        
        passed = len(differences) == 0
        error_msg = f"Field differences: {differences}" if differences else ""
        
        return TestResult(
            test_name=test_name,
            passed=passed,
            localhost_data=localhost_data,
            production_data=production_data,
            error_message=error_msg,
            details={'differences': differences}
        )
    
    def compare_list_data(self, endpoint: str, params: Dict = None, compare_top_n: int = 3) -> TestResult:
        """Compare list-based endpoints (teams, players, etc.)"""
        test_name = f"{endpoint}: {params or 'no params'}"
        
        localhost_success, localhost_data = self.make_request(LOCALHOST_API, endpoint, params)
        production_success, production_data = self.make_request(PRODUCTION_API, endpoint, params)
        
        if not localhost_success or not production_success:
            return TestResult(
                test_name=test_name,
                passed=False,
                localhost_data=localhost_data if localhost_success else None,
                production_data=production_data if production_success else None,
                error_message="API request failed"
            )
        
        differences = {}
        
        # Compare counts
        localhost_count = localhost_data.get('count', len(localhost_data) if isinstance(localhost_data, list) else 0)
        production_count = production_data.get('count', len(production_data) if isinstance(production_data, list) else 0)
        
        if localhost_count != production_count:
            differences['count'] = {
                'localhost': localhost_count,
                'production': production_count
            }
        
        # Get list data (handle both formats: {'results': []} and direct list)
        localhost_list = localhost_data.get('results', localhost_data) if isinstance(localhost_data, dict) else localhost_data
        production_list = production_data.get('results', production_data) if isinstance(production_data, dict) else production_data
        
        if isinstance(localhost_list, list) and isinstance(production_list, list):
            # Compare top N items
            top_n = min(compare_top_n, len(localhost_list), len(production_list))
            if top_n > 0:
                for i in range(top_n):
                    local_item = localhost_list[i]
                    prod_item = production_list[i]
                    
                    # Compare key identifying fields
                    local_id = local_item.get('id')
                    prod_id = prod_item.get('id')
                    
                    if local_id != prod_id:
                        differences[f'top_{i+1}_id'] = {
                            'localhost': local_id,
                            'production': prod_id
                        }
        
        passed = len(differences) == 0
        error_msg = f"Data differences: {differences}" if differences else ""
        
        return TestResult(
            test_name=test_name,
            passed=passed,
            localhost_data=localhost_data,
            production_data=production_data,
            error_message=error_msg,
            details={'differences': differences}
        )

    # ===============================
    # ROUTER-SPECIFIC TEST METHODS
    # ===============================
    
    def test_awards_router(self) -> List[TestResult]:
        """Test awards router endpoints"""
        self.logger.info("Testing awards router...")
        results = []
        
        test_cases = [
            ("/awards", {"season": TEST_SEASON}),
            ("/awards", {"season": TEST_SEASON, "limit": 10}),
            ("/awards", {"team_id": SAMPLE_TEAM_IDS[0], "season": TEST_SEASON}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_list_data(endpoint, params)
            results.append(result)
            self.logger.info(f"Awards {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_current_router(self) -> List[TestResult]:
        """Test current router endpoints"""
        self.logger.info("Testing current router...")
        results = []
        
        test_cases = [
            ("/current", {}),
            ("/current", {"league": "SBa"}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['season', 'week'])
            results.append(result)
            self.logger.info(f"Current {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_decisions_router(self) -> List[TestResult]:
        """Test decisions router endpoints"""
        self.logger.info("Testing decisions router...")
        results = []
        
        test_cases = [
            ("/decisions", {"season": TEST_SEASON, "limit": 10}),
            ("/decisions", {"season": TEST_SEASON, "player_id": SAMPLE_PLAYER_IDS[0]}),
            ("/decisions", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Decisions {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_divisions_router(self) -> List[TestResult]:
        """Test divisions router endpoints"""
        self.logger.info("Testing divisions router...")
        results = []
        
        test_cases = [
            ("/divisions", {"season": TEST_SEASON}),
            ("/divisions", {"season": TEST_SEASON, "league": "SBa"}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_list_data(endpoint, params)
            results.append(result)
            self.logger.info(f"Divisions {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_draftdata_router(self) -> List[TestResult]:
        """Test draftdata router endpoints"""
        self.logger.info("Testing draftdata router...")
        results = []
        
        test_cases = [
            ("/draftdata", {"season": TEST_SEASON}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['current_pick', 'current_round'])
            results.append(result)
            self.logger.info(f"Draft data {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_draftlist_router(self) -> List[TestResult]:
        """Test draftlist router endpoints - REQUIRES AUTHENTICATION"""
        self.logger.info("Testing draftlist router (authentication required)...")
        results = []
        
        # Note: This endpoint requires authentication, which test suite doesn't provide
        # This is expected behavior and not a migration issue
        self.logger.info("Skipping draftlist tests - authentication required (expected)")
        
        return results
    
    def test_draftpicks_router(self) -> List[TestResult]:
        """Test draftpicks router endpoints"""
        self.logger.info("Testing draftpicks router...")
        results = []
        
        test_cases = [
            ("/draftpicks", {"season": TEST_SEASON, "limit": 10}),
            ("/draftpicks", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
            ("/draftpicks", {"season": TEST_SEASON, "round": 1}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Draft picks {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_injuries_router(self) -> List[TestResult]:
        """Test injuries router endpoints"""
        self.logger.info("Testing injuries router...")
        results = []
        
        test_cases = [
            ("/injuries", {"season": TEST_SEASON, "limit": 10}),
            ("/injuries", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
            ("/injuries", {"season": TEST_SEASON, "active": True}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Injuries {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_keepers_router(self) -> List[TestResult]:
        """Test keepers router endpoints"""
        self.logger.info("Testing keepers router...")
        results = []
        
        test_cases = [
            ("/keepers", {"season": TEST_SEASON, "limit": 10}),
            ("/keepers", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Keepers {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_managers_router(self) -> List[TestResult]:
        """Test managers router endpoints"""
        self.logger.info("Testing managers router...")
        results = []
        
        test_cases = [
            ("/managers", {}),
            ("/managers", {"limit": 10}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_list_data(endpoint, params)
            results.append(result)
            self.logger.info(f"Managers {params}: {'PASS' if result.passed else 'FAIL'}")
        
        # Test individual manager
        if SAMPLE_MANAGER_IDS:
            for manager_id in SAMPLE_MANAGER_IDS[:2]:  # Test first 2
                result = self.compare_basic_data(f"/managers/{manager_id}", {})
                results.append(result)
                self.logger.info(f"Manager {manager_id}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_players_router(self) -> List[TestResult]:
        """Test players router endpoints"""
        self.logger.info("Testing players router...")
        results = []
        
        test_cases = [
            ("/players", {"season": TEST_SEASON, "limit": 10}),
            ("/players", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
            ("/players", {"season": TEST_SEASON, "pos": "OF", "limit": 5}),
            ("/players", {"season": TEST_SEASON, "active": True, "limit": 10}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Players {params}: {'PASS' if result.passed else 'FAIL'}")
        
        # Test individual players
        for player_id in SAMPLE_PLAYER_IDS[:3]:  # Test first 3
            result = self.compare_basic_data(f"/players/{player_id}", {})
            results.append(result)
            self.logger.info(f"Player {player_id}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_results_router(self) -> List[TestResult]:
        """Test results router endpoints"""
        self.logger.info("Testing results router...")
        results = []
        
        test_cases = [
            ("/results", {"season": TEST_SEASON, "limit": 10}),
            ("/results", {"season": TEST_SEASON, "week": 1}),
            ("/results", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Results {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_sbaplayers_router(self) -> List[TestResult]:
        """Test sbaplayers router endpoints"""
        self.logger.info("Testing sbaplayers router...")
        results = []
        
        test_cases = [
            ("/sbaplayers", {"limit": 10}),
            ("/sbaplayers", {"active": True}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"SBA players {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_schedules_router(self) -> List[TestResult]:
        """Test schedules router endpoints"""
        self.logger.info("Testing schedules router...")
        results = []
        
        test_cases = [
            ("/schedules", {"season": TEST_SEASON, "limit": 10}),
            ("/schedules", {"season": TEST_SEASON, "week": 1}),
            ("/schedules", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Schedules {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_standings_router(self) -> List[TestResult]:
        """Test standings router endpoints"""
        self.logger.info("Testing standings router...")
        results = []
        
        test_cases = [
            ("/standings", {"season": TEST_SEASON}),
            ("/standings", {"season": TEST_SEASON, "league": "SBa"}),
            ("/standings", {"season": TEST_SEASON, "division": "Milkshake"}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_list_data(endpoint, params)
            results.append(result)
            self.logger.info(f"Standings {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_stratgame_router(self) -> List[TestResult]:
        """Test games router endpoints (stratgame was renamed to games)"""
        self.logger.info("Testing games router...")
        results = []
        
        test_cases = [
            ("/games", {"season": TEST_SEASON, "limit": 10}),
            ("/games", {"season": TEST_SEASON, "week": 1}),
            ("/games", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Games {params}: {'PASS' if result.passed else 'FAIL'}")
        
        # Test individual games
        for game_id in SAMPLE_GAME_IDS[:2]:  # Test first 2
            result = self.compare_basic_data(f"/games/{game_id}", {})
            results.append(result)
            self.logger.info(f"Game {game_id}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_teams_router(self) -> List[TestResult]:
        """Test teams router endpoints"""
        self.logger.info("Testing teams router...")
        results = []
        
        test_cases = [
            ("/teams", {"season": TEST_SEASON}),
            ("/teams", {"season": TEST_SEASON, "division": "Milkshake"}),
            ("/teams", {"season": TEST_SEASON, "league": "SBa"}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_list_data(endpoint, params)
            results.append(result)
            self.logger.info(f"Teams {params}: {'PASS' if result.passed else 'FAIL'}")
        
        # Test individual teams
        for team_id in SAMPLE_TEAM_IDS[:3]:  # Test first 3
            result = self.compare_basic_data(f"/teams/{team_id}", {})
            results.append(result)
            self.logger.info(f"Team {team_id}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_transactions_router(self) -> List[TestResult]:
        """Test transactions router endpoints"""
        self.logger.info("Testing transactions router...")
        results = []
        
        test_cases = [
            ("/transactions", {"season": TEST_SEASON, "limit": 10}),
            ("/transactions", {"season": TEST_SEASON, "team_id": SAMPLE_TEAM_IDS[0]}),
            ("/transactions", {"season": TEST_SEASON, "trans_type": "trade"}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Transactions {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results
    
    def test_stratplay_router(self) -> List[TestResult]:
        """Test stratplay router endpoints (comprehensive)"""
        self.logger.info("Testing stratplay router...")
        results = []
        
        # Basic plays endpoint
        test_cases = [
            ("/plays", {"season": TEST_SEASON, "limit": 10}),
            ("/plays", {"season": TEST_SEASON, "game_id": SAMPLE_GAME_IDS[0]}),
            ("/plays", {"season": TEST_SEASON, "batter_id": SAMPLE_PLAYER_IDS[0], "limit": 5}),
        ]
        
        for endpoint, params in test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Plays {params}: {'PASS' if result.passed else 'FAIL'}")
        
        # Batting stats (already tested in PostgreSQL fixes)
        batting_test_cases = [
            ("/plays/batting", {"season": TEST_SEASON, "group_by": "player", "limit": 5}),
            ("/plays/batting", {"season": TEST_SEASON, "group_by": "team", "limit": 5}),
            ("/plays/batting", {"season": TEST_SEASON, "group_by": "playerteam", "limit": 5}),
        ]
        
        for endpoint, params in batting_test_cases:
            result = self.compare_basic_data(endpoint, params, ['count'])
            results.append(result)
            self.logger.info(f"Batting stats {params}: {'PASS' if result.passed else 'FAIL'}")
        
        return results

    # ===============================
    # TEST RUNNER METHODS
    # ===============================
    
    def run_all_tests(self) -> None:
        """Run the complete test suite for all routers"""
        self.logger.info("Starting Comprehensive API Data Integrity Test Suite")
        self.logger.info(f"Localhost API: {LOCALHOST_API}")
        self.logger.info(f"Production API: {PRODUCTION_API}")
        self.logger.info(f"Test Season: {TEST_SEASON}")
        self.logger.info("=" * 60)
        
        # Run all router tests
        router_tests = [
            self.test_awards_router,
            self.test_current_router,
            self.test_decisions_router,
            self.test_divisions_router,
            self.test_draftdata_router,
            self.test_draftlist_router,
            self.test_draftpicks_router,
            self.test_injuries_router,
            self.test_keepers_router,
            self.test_managers_router,
            self.test_players_router,
            self.test_results_router,
            self.test_sbaplayers_router,
            self.test_schedules_router,
            self.test_standings_router,
            self.test_stratgame_router,
            self.test_teams_router,
            self.test_transactions_router,
            self.test_stratplay_router,
        ]
        
        for test_func in router_tests:
            try:
                self.results.extend(test_func())
            except Exception as e:
                self.logger.error(f"Error in {test_func.__name__}: {e}")
        
        # Generate summary
        self.generate_summary()
    
    def run_router_tests(self, router_name: str) -> None:
        """Run tests for a specific router"""
        router_map = {
            'awards': self.test_awards_router,
            'current': self.test_current_router,
            'decisions': self.test_decisions_router,
            'divisions': self.test_divisions_router,
            'draftdata': self.test_draftdata_router,
            'draftlist': self.test_draftlist_router,
            'draftpicks': self.test_draftpicks_router,
            'injuries': self.test_injuries_router,
            'keepers': self.test_keepers_router,
            'managers': self.test_managers_router,
            'players': self.test_players_router,
            'results': self.test_results_router,
            'sbaplayers': self.test_sbaplayers_router,
            'schedules': self.test_schedules_router,
            'standings': self.test_standings_router,
            'stratgame': self.test_stratgame_router,
            'teams': self.test_teams_router,
            'transactions': self.test_transactions_router,
            'stratplay': self.test_stratplay_router,
        }
        
        if router_name not in router_map:
            self.logger.error(f"Unknown router: {router_name}")
            self.logger.info(f"Available routers: {', '.join(router_map.keys())}")
            return
        
        self.logger.info(f"Running tests for {router_name} router only")
        self.results.extend(router_map[router_name]())
        self.generate_summary()
    
    def generate_summary(self) -> None:
        """Generate and display test summary"""
        total_tests = len(self.results)
        passed_tests = sum(1 for r in self.results if r.passed)
        failed_tests = total_tests - passed_tests
        
        success_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0
        
        self.logger.info("=" * 60)
        self.logger.info("TEST SUMMARY")
        self.logger.info("=" * 60)
        self.logger.info(f"Total Tests: {total_tests}")
        self.logger.info(f"Passed: {passed_tests}")
        self.logger.info(f"Failed: {failed_tests}")
        self.logger.info(f"Success Rate: {success_rate:.1f}%")
        
        if failed_tests > 0:
            self.logger.info("\nFAILED TESTS:")
            self.logger.info("-" * 40)
            for result in self.results:
                if not result.passed:
                    self.logger.info(f"❌ {result.test_name}")
                    self.logger.info(f"   Error: {result.error_message}")
        
        # Save detailed results
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        results_file = f"logs/comprehensive_api_results_{timestamp}.json"
        
        results_data = {
            'timestamp': timestamp,
            'total_tests': total_tests,
            'passed_tests': passed_tests,
            'failed_tests': failed_tests,
            'success_rate': success_rate,
            'results': [
                {
                    'test_name': r.test_name,
                    'passed': r.passed,
                    'error_message': r.error_message,
                    'details': r.details
                }
                for r in self.results
            ]
        }
        
        with open(results_file, 'w') as f:
            json.dump(results_data, f, indent=2)
        
        self.logger.info(f"\nDetailed results saved to: {results_file}")

def main():
    """Main entry point"""
    parser = argparse.ArgumentParser(description='Comprehensive API Data Integrity Test Suite')
    parser.add_argument('--verbose', '-v', action='store_true', help='Enable verbose logging')
    parser.add_argument('--router', '-r', type=str, help='Test specific router only')
    
    args = parser.parse_args()
    
    tester = ComprehensiveAPITester(verbose=args.verbose)
    
    try:
        if args.router:
            tester.run_router_tests(args.router)
        else:
            tester.run_all_tests()
    except KeyboardInterrupt:
        tester.logger.info("\nTest suite interrupted by user")
        sys.exit(1)
    except Exception as e:
        tester.logger.error(f"Test suite failed with error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()