"""
Comprehensive Test Runner for Granular Permissions and Reporting System

This module provides utilities for running all tests, generating coverage reports,
and validating the complete system functionality.
"""

import os
import sys
import time
import unittest
from django.test.runner import DiscoverRunner
from django.test import TestCase
from django.core.management import call_command
from django.conf import settings
from django.db import connection
from django.core.cache import cache
from io import StringIO
import coverage


class ComprehensiveTestRunner(DiscoverRunner):
    """
    Custom test runner for comprehensive testing with coverage and performance metrics
    """
    
    def __init__(self, *args, **kwargs):
        self.coverage = None
        self.start_time = None
        self.test_results = {}
        super().__init__(*args, **kwargs)
    
    def setup_test_environment(self, **kwargs):
        """Set up test environment with coverage tracking"""
        super().setup_test_environment(**kwargs)
        
        # Initialize coverage tracking
        self.coverage = coverage.Coverage(
            source=['users', 'reports', 'utils'],
            omit=[
                '*/migrations/*',
                '*/tests/*',
                '*/venv/*',
                '*/env/*',
                'manage.py',
                '*/settings/*'
            ]
        )
        self.coverage.start()
        
        # Clear cache
        cache.clear()
        
        # Record start time
        self.start_time = time.time()
        
        print("=" * 70)
        print("GRANULAR PERMISSIONS & REPORTING SYSTEM - COMPREHENSIVE TEST SUITE")
        print("=" * 70)
        print(f"Started at: {time.strftime('%Y-%m-%d %H:%M:%S')}")
        print()
    
    def teardown_test_environment(self, **kwargs):
        """Tear down test environment and generate reports"""
        # Stop coverage tracking
        if self.coverage:
            self.coverage.stop()
            self.coverage.save()
        
        # Calculate total execution time
        total_time = time.time() - self.start_time if self.start_time else 0
        
        print()
        print("=" * 70)
        print("TEST EXECUTION SUMMARY")
        print("=" * 70)
        print(f"Total execution time: {total_time:.2f} seconds")
        
        # Generate coverage report
        self.generate_coverage_report()
        
        # Generate performance report
        self.generate_performance_report()
        
        super().teardown_test_environment(**kwargs)
    
    def generate_coverage_report(self):
        """Generate coverage report"""
        if not self.coverage:
            return
        
        print("\nCOVERAGE REPORT:")
        print("-" * 50)
        
        # Console coverage report
        output = StringIO()
        self.coverage.report(file=output, show_missing=True)
        print(output.getvalue())
        
        # HTML coverage report
        try:
            html_dir = os.path.join(settings.BASE_DIR, 'htmlcov')
            self.coverage.html_report(directory=html_dir)
            print(f"\nDetailed HTML coverage report generated in: {html_dir}")
        except Exception as e:
            print(f"Could not generate HTML coverage report: {e}")
    
    def generate_performance_report(self):
        """Generate performance report"""
        print("\nPERFORMANCE METRICS:")
        print("-" * 50)
        
        # Database query count
        if hasattr(connection, 'queries'):
            query_count = len(connection.queries)
            print(f"Total database queries: {query_count}")
        
        # Cache statistics
        try:
            cache_stats = cache._cache.get_stats()
            if cache_stats:
                print(f"Cache hits: {cache_stats[0].get('get_hits', 'N/A')}")
                print(f"Cache misses: {cache_stats[0].get('get_misses', 'N/A')}")
        except:
            print("Cache statistics not available")
    
    def run_tests(self, test_labels, **kwargs):
        """Run tests with additional validation"""
        print("Running comprehensive test suite...")
        print()
        
        # Run the actual tests
        result = super().run_tests(test_labels, **kwargs)
        
        # Additional validation
        self.validate_test_completeness()
        
        return result
    
    def validate_test_completeness(self):
        """Validate that all required components are tested"""
        print("\nTEST COMPLETENESS VALIDATION:")
        print("-" * 50)
        
        required_test_modules = [
            'users.tests.test_permission_services',
            'users.tests.test_analytics_services',
            'users.tests.test_export_functionality',
            'users.tests.test_integration_workflows',
            'users.tests.test_permission_migration',
            'users.tests.test_portfolio_snapshot_service'
        ]
        
        missing_modules = []
        for module in required_test_modules:
            try:
                __import__(module)
                print(f"✓ {module}")
            except ImportError:
                missing_modules.append(module)
                print(f"✗ {module} - MISSING")
        
        if missing_modules:
            print(f"\nWarning: {len(missing_modules)} test modules are missing")
        else:
            print("\n✓ All required test modules are present")


class TestSuiteValidator:
    """
    Validator for ensuring test suite completeness and quality
    """
    
    def __init__(self):
        self.validation_results = {}
    
    def validate_unit_tests(self):
        """Validate unit test coverage"""
        print("Validating unit test coverage...")
        
        required_components = [
            'PagePermissionManager',
            'RolePermissionTemplateManager',
            'PermissionCacheService',
            'PortfolioSnapshotService',
            'ClientGrowthAnalytics',
            'EnhancedPDFService',
            'ExportService',
            'AdvancedFilteringService',
            'BatchProcessingService'
        ]
        
        tested_components = []
        
        # Check if each component has tests
        for component in required_components:
            # This is a simplified check - in practice, you'd scan test files
            test_exists = self.check_component_tests(component)
            if test_exists:
                tested_components.append(component)
        
        coverage_percentage = (len(tested_components) / len(required_components)) * 100
        
        self.validation_results['unit_tests'] = {
            'total_components': len(required_components),
            'tested_components': len(tested_components),
            'coverage_percentage': coverage_percentage,
            'missing_tests': [c for c in required_components if c not in tested_components]
        }
        
        print(f"Unit test coverage: {coverage_percentage:.1f}%")
        return coverage_percentage >= 90
    
    def validate_integration_tests(self):
        """Validate integration test coverage"""
        print("Validating integration test coverage...")
        
        required_workflows = [
            'permission_setup_workflow',
            'permission_inheritance_workflow',
            'bulk_permission_management',
            'permission_audit_workflow',
            'report_generation_workflow'
        ]
        
        # Check if integration tests exist for each workflow
        tested_workflows = []
        for workflow in required_workflows:
            if self.check_workflow_tests(workflow):
                tested_workflows.append(workflow)
        
        coverage_percentage = (len(tested_workflows) / len(required_workflows)) * 100
        
        self.validation_results['integration_tests'] = {
            'total_workflows': len(required_workflows),
            'tested_workflows': len(tested_workflows),
            'coverage_percentage': coverage_percentage
        }
        
        print(f"Integration test coverage: {coverage_percentage:.1f}%")
        return coverage_percentage >= 80
    
    def validate_performance_tests(self):
        """Validate performance test coverage"""
        print("Validating performance test coverage...")
        
        performance_areas = [
            'bulk_permission_checking',
            'large_dataset_export',
            'analytics_calculation',
            'concurrent_access'
        ]
        
        tested_areas = []
        for area in performance_areas:
            if self.check_performance_tests(area):
                tested_areas.append(area)
        
        coverage_percentage = (len(tested_areas) / len(performance_areas)) * 100
        
        self.validation_results['performance_tests'] = {
            'total_areas': len(performance_areas),
            'tested_areas': len(tested_areas),
            'coverage_percentage': coverage_percentage
        }
        
        print(f"Performance test coverage: {coverage_percentage:.1f}%")
        return coverage_percentage >= 75
    
    def validate_security_tests(self):
        """Validate security test coverage"""
        print("Validating security test coverage...")
        
        security_areas = [
            'permission_bypass_protection',
            'sql_injection_protection',
            'privilege_escalation_protection',
            'data_exposure_protection'
        ]
        
        tested_areas = []
        for area in security_areas:
            if self.check_security_tests(area):
                tested_areas.append(area)
        
        coverage_percentage = (len(tested_areas) / len(security_areas)) * 100
        
        self.validation_results['security_tests'] = {
            'total_areas': len(security_areas),
            'tested_areas': len(tested_areas),
            'coverage_percentage': coverage_percentage
        }
        
        print(f"Security test coverage: {coverage_percentage:.1f}%")
        return coverage_percentage >= 80
    
    def check_component_tests(self, component):
        """Check if component has tests (simplified implementation)"""
        # In a real implementation, this would scan test files for test methods
        # related to the component
        return True  # Assuming tests exist for demonstration
    
    def check_workflow_tests(self, workflow):
        """Check if workflow has integration tests"""
        return True  # Assuming tests exist for demonstration
    
    def check_performance_tests(self, area):
        """Check if performance tests exist for area"""
        return True  # Assuming tests exist for demonstration
    
    def check_security_tests(self, area):
        """Check if security tests exist for area"""
        return True  # Assuming tests exist for demonstration
    
    def generate_validation_report(self):
        """Generate comprehensive validation report"""
        print("\n" + "=" * 70)
        print("TEST SUITE VALIDATION REPORT")
        print("=" * 70)
        
        overall_score = 0
        total_categories = 0
        
        for category, results in self.validation_results.items():
            print(f"\n{category.upper().replace('_', ' ')}:")
            print(f"  Coverage: {results['coverage_percentage']:.1f}%")
            
            if 'missing_tests' in results and results['missing_tests']:
                print(f"  Missing tests for: {', '.join(results['missing_tests'])}")
            
            overall_score += results['coverage_percentage']
            total_categories += 1
        
        if total_categories > 0:
            overall_score = overall_score / total_categories
            print(f"\nOVERALL TEST SUITE SCORE: {overall_score:.1f}%")
            
            if overall_score >= 90:
                print("✓ EXCELLENT - Test suite is comprehensive")
            elif overall_score >= 80:
                print("✓ GOOD - Test suite has good coverage")
            elif overall_score >= 70:
                print("⚠ FAIR - Test suite needs improvement")
            else:
                print("✗ POOR - Test suite requires significant work")
        
        return overall_score
    
    def run_full_validation(self):
        """Run full test suite validation"""
        print("Running comprehensive test suite validation...")
        print()
        
        validations = [
            self.validate_unit_tests(),
            self.validate_integration_tests(),
            self.validate_performance_tests(),
            self.validate_security_tests()
        ]
        
        overall_score = self.generate_validation_report()
        
        return all(validations), overall_score


def run_comprehensive_tests():
    """
    Main function to run comprehensive tests with validation
    """
    print("Starting comprehensive test suite...")
    
    # Validate test suite first
    validator = TestSuiteValidator()
    is_valid, score = validator.run_full_validation()
    
    if not is_valid:
        print("\nWarning: Test suite validation failed. Some tests may be missing.")
    
    # Run the actual tests
    print("\n" + "=" * 70)
    print("EXECUTING TEST SUITE")
    print("=" * 70)
    
    # Use Django's test command with our custom runner
    call_command('test', 
                'users.tests',
                verbosity=2,
                keepdb=True,
                parallel=1)
    
    print("\nComprehensive test suite completed!")
    return is_valid, score


if __name__ == '__main__':
    # Run comprehensive tests
    is_valid, score = run_comprehensive_tests()
    
    # Exit with appropriate code
    if is_valid and score >= 80:
        sys.exit(0)  # Success
    else:
        sys.exit(1)  # Failure