"""
Test suite for production configuration and deployment readiness.

Related to Issue #145: Phase 4 - Production Readiness and Release (Week 6)
Tests production configuration management, deployment validation, security settings,
migration tools, and release preparation capabilities.
"""

import pytest
import tempfile
import shutil
import yaml
import json
import os
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from markitect.production.configuration import (
    ProductionConfiguration,
    ConfigurationValidator,
    DeploymentValidator,
    SecurityValidator,
    MigrationManager,
    ReleaseValidator,
    ConfigurationTemplate
)


class TestProductionConfiguration:
    """Test production configuration and deployment readiness."""

    @pytest.fixture
    def temp_workspace(self):
        """Create temporary workspace for testing."""
        temp_dir = tempfile.mkdtemp()
        yield Path(temp_dir)
        shutil.rmtree(temp_dir, ignore_errors=True)

    @pytest.fixture
    def production_config(self, temp_workspace):
        """Create ProductionConfiguration instance."""
        return ProductionConfiguration(
            workspace_path=temp_workspace,
            environment="production",
            validation_level="strict"
        )

    @pytest.fixture
    def sample_config_data(self):
        """Sample production configuration data."""
        return {
            "asset_management": {
                "reliability": {
                    "enable_backups": True,
                    "backup_frequency": "daily",
                    "max_backup_age_days": 30,
                    "integrity_checks": True
                },
                "error_handling": {
                    "log_level": "INFO",
                    "error_reporting": True,
                    "recovery_mode": "auto",
                    "confirmation_required": True
                },
                "monitoring": {
                    "enabled": True,
                    "metrics_collection": True,
                    "performance_alerts": True,
                    "resource_limits": {
                        "max_memory_mb": 200,
                        "max_disk_space_gb": 10
                    }
                },
                "security": {
                    "validate_file_types": True,
                    "scan_for_malware": True,
                    "restrict_symlink_targets": True,
                    "audit_operations": True
                }
            }
        }

    def test_production_configuration_validation(self, production_config, sample_config_data):
        """Test comprehensive production configuration validation."""
        validator = ConfigurationValidator()

        # Test valid configuration
        result = validator.validate_configuration(sample_config_data)

        assert result.is_valid is True
        assert result.validation_errors == []
        assert result.warnings is not None
        assert result.security_compliance is True

        # Test invalid configuration
        invalid_config = sample_config_data.copy()
        invalid_config["asset_management"]["monitoring"]["resource_limits"]["max_memory_mb"] = -100

        invalid_result = validator.validate_configuration(invalid_config)

        assert invalid_result.is_valid is False
        assert len(invalid_result.validation_errors) > 0
        assert any("negative" in error.lower() for error in invalid_result.validation_errors)

    def test_security_configuration_validation(self, production_config, sample_config_data):
        """Test security configuration validation."""
        security_validator = SecurityValidator()

        # Test security compliance
        security_result = security_validator.validate_security_settings(
            sample_config_data["asset_management"]["security"]
        )

        assert security_result.compliance_score >= 0.8  # 80% compliance minimum
        assert security_result.file_validation_enabled is True
        assert security_result.audit_logging_enabled is True
        assert security_result.access_controls_configured is True

        # Test insecure configuration
        insecure_config = {
            "validate_file_types": False,
            "scan_for_malware": False,
            "restrict_symlink_targets": False,
            "audit_operations": False
        }

        insecure_result = security_validator.validate_security_settings(insecure_config)

        assert insecure_result.compliance_score < 0.5  # Poor compliance
        assert len(insecure_result.security_risks) > 0

    def test_deployment_environment_validation(self, production_config):
        """Test deployment environment validation."""
        deployment_validator = DeploymentValidator()

        # Test production environment readiness
        environment_checks = [
            "python_version",
            "dependencies",
            "permissions",
            "storage_space",
            "network_connectivity",
            "security_settings"
        ]

        for check in environment_checks:
            result = deployment_validator.validate_environment_requirement(check)

            assert result.requirement_name == check
            assert result.status in ["PASS", "FAIL", "WARNING"]
            if result.status == "FAIL":
                assert result.remediation_steps is not None

    def test_configuration_template_generation(self, production_config, temp_workspace):
        """Test configuration template generation for different environments."""
        template_generator = ConfigurationTemplate(
            environment="test",
            configuration={}
        )

        environments = ["development", "staging", "production"]

        for env in environments:
            template = ConfigurationTemplate(
                environment=env,
                configuration={
                    "features": ["asset_management", "monitoring", "security"],
                    "database": {"host": "localhost", "port": 5432},
                    "logging": {"level": "INFO"}
                }
            )

            assert template.environment == env
            assert template.configuration is not None
            assert "features" in template.configuration
            assert "asset_management" in template.configuration["features"]

            # Save and validate template
            template_file = temp_workspace / f"markitect_{env}.yaml"
            template.save_to_file(template_file)

            assert template_file.exists()

            # Verify it's valid YAML
            loaded_config = yaml.safe_load(template_file.read_text())
            assert loaded_config is not None

    def test_configuration_migration_between_versions(self, production_config, temp_workspace):
        """Test configuration migration between versions."""
        migration_manager = MigrationManager()

        # Create old version configuration
        old_config = {
            "version": "1.0",
            "asset_management": {
                "backup_enabled": True,  # Old format
                "log_level": "DEBUG"
            }
        }

        old_config_file = temp_workspace / "old_config.yaml"
        with open(old_config_file, 'w') as f:
            yaml.dump(old_config, f)

        # Migrate to new version
        migration_result = migration_manager.migrate_configuration(
            source_file=old_config_file,
            target_version="2.0"
        )

        assert migration_result.success is True
        assert migration_result.source_version == "1.0"
        assert migration_result.target_version == "2.0"
        assert migration_result.migrated_config is not None

        # Verify migration transformations
        migrated = migration_result.migrated_config
        assert migrated["version"] == "2.0"
        assert "reliability" in migrated["asset_management"]
        assert migrated["asset_management"]["reliability"]["enable_backups"] is True

    def test_backward_compatibility_validation(self, production_config):
        """Test backward compatibility validation."""
        compatibility_validator = production_config.get_compatibility_validator()

        # Test compatibility matrix
        version_pairs = [
            ("1.0", "1.1"),  # Minor version - should be compatible
            ("1.5", "2.0"),  # Major version - might have breaking changes
            ("2.0", "1.9")   # Downgrade - not supported
        ]

        for source_version, target_version in version_pairs:
            compatibility = compatibility_validator.check_compatibility(
                source_version=source_version,
                target_version=target_version
            )

            assert compatibility.source_version == source_version
            assert compatibility.target_version == target_version
            assert compatibility.compatibility_level in ["FULL", "PARTIAL", "BREAKING", "UNSUPPORTED"]

            if compatibility.compatibility_level == "BREAKING":
                assert compatibility.breaking_changes is not None
                assert len(compatibility.breaking_changes) > 0

    def test_feature_flag_management(self, production_config):
        """Test feature flag management for gradual rollouts."""
        feature_manager = production_config.get_feature_manager()

        # Configure feature flags
        feature_flags = {
            "new_asset_discovery": {"enabled": True, "rollout_percentage": 50},
            "enhanced_monitoring": {"enabled": True, "rollout_percentage": 100},
            "experimental_cache": {"enabled": False, "rollout_percentage": 0}
        }

        feature_manager.configure_flags(feature_flags)

        # Test feature flag evaluation
        for feature_name, config in feature_flags.items():
            is_enabled = feature_manager.is_feature_enabled(
                feature_name=feature_name,
                user_id="test_user_123"
            )

            if config["rollout_percentage"] == 100:
                assert is_enabled is True
            elif config["rollout_percentage"] == 0:
                assert is_enabled is False
            # For partial rollout, result depends on user_id hash

    def test_installation_scripts_for_all_platforms(self, production_config):
        """Test installation scripts for all platforms."""
        installer_generator = production_config.get_installer_generator()

        platforms = ["linux", "macos", "windows"]

        for platform in platforms:
            installer = installer_generator.generate_installer(
                platform=platform,
                installation_type="standard",
                include_dependencies=True
            )

            assert installer.platform == platform
            assert installer.script_content is not None
            assert installer.dependencies is not None

            # Validate script syntax for platform
            validation_result = installer.validate_script_syntax()
            assert validation_result.is_valid is True

    def test_package_manager_integration(self, production_config):
        """Test package manager integration (pip, apt, brew)."""
        package_integrator = production_config.get_package_integrator()

        package_managers = [
            {"name": "pip", "platform": "python", "command": "pip install"},
            {"name": "apt", "platform": "ubuntu", "command": "apt install"},
            {"name": "brew", "platform": "macos", "command": "brew install"}
        ]

        for pm in package_managers:
            integration_result = package_integrator.test_package_manager_integration(
                package_manager=pm["name"],
                test_package="markitect"
            )

            assert integration_result.package_manager == pm["name"]
            assert integration_result.available is not None
            assert integration_result.installation_command is not None

    def test_container_images_and_deployment_configs(self, production_config, temp_workspace):
        """Test container images and deployment configs."""
        container_generator = production_config.get_container_generator()

        # Generate Dockerfile
        dockerfile_content = container_generator.generate_dockerfile(
            base_image="python:3.9-slim",
            features=["asset_management", "monitoring"],
            optimization_level="production"
        )

        dockerfile_path = temp_workspace / "Dockerfile"
        dockerfile_path.write_text(dockerfile_content)

        assert dockerfile_path.exists()
        assert "FROM python:3.9-slim" in dockerfile_content
        assert "COPY . /app" in dockerfile_content
        assert "CMD" in dockerfile_content

        # Generate docker-compose configuration
        compose_config = container_generator.generate_docker_compose(
            services=["markitect", "monitoring", "backup"],
            environment="production"
        )

        compose_path = temp_workspace / "docker-compose.yml"
        with open(compose_path, 'w') as f:
            yaml.dump(compose_config, f)

        assert compose_path.exists()
        loaded_compose = yaml.safe_load(compose_path.read_text())
        assert "services" in loaded_compose
        assert "markitect" in loaded_compose["services"]

    def test_ci_cd_pipeline_configuration(self, production_config, temp_workspace):
        """Test CI/CD pipeline for automated releases."""
        pipeline_generator = production_config.get_pipeline_generator()

        # Generate GitHub Actions workflow
        github_workflow = pipeline_generator.generate_github_actions_workflow(
            triggers=["push", "pull_request"],
            test_environments=["ubuntu-latest", "windows-latest", "macos-latest"],
            deployment_environments=["staging", "production"]
        )

        workflow_path = temp_workspace / ".github" / "workflows" / "ci-cd.yml"
        workflow_path.parent.mkdir(parents=True, exist_ok=True)
        with open(workflow_path, 'w') as f:
            yaml.dump(github_workflow, f)

        assert workflow_path.exists()
        workflow_content = yaml.safe_load(workflow_path.read_text())
        assert "on" in workflow_content
        assert "jobs" in workflow_content

    def test_monitoring_and_observability_setup(self, production_config):
        """Test monitoring and observability setup."""
        monitoring_configurator = production_config.get_monitoring_configurator()

        # Configure monitoring stack
        monitoring_config = monitoring_configurator.generate_monitoring_config(
            metrics_backend="prometheus",
            logging_backend="elasticsearch",
            alerting_backend="alertmanager"
        )

        assert monitoring_config.metrics_config is not None
        assert monitoring_config.logging_config is not None
        assert monitoring_config.alerting_config is not None

        # Test alert rules generation
        alert_rules = monitoring_configurator.generate_alert_rules(
            error_rate_threshold=0.05,
            response_time_threshold=100,
            memory_usage_threshold=80
        )

        assert len(alert_rules) > 0
        assert any("error_rate" in rule.name for rule in alert_rules)

    def test_semantic_versioning_implementation(self, production_config):
        """Test semantic versioning implementation."""
        version_manager = production_config.get_version_manager()

        # Test version parsing
        version_info = version_manager.parse_version("1.2.3-beta.1+build.123")

        assert version_info.major == 1
        assert version_info.minor == 2
        assert version_info.patch == 3
        assert version_info.prerelease == "beta.1"
        assert version_info.build == "build.123"

        # Test version comparison
        versions = ["1.0.0", "1.0.1", "1.1.0", "2.0.0-alpha", "2.0.0"]
        sorted_versions = version_manager.sort_versions(versions)

        assert sorted_versions[0] == "1.0.0"
        assert sorted_versions[-1] == "2.0.0"

        # Test version increment
        next_patch = version_manager.increment_version("1.2.3", "patch")
        assert next_patch == "1.2.4"

        next_minor = version_manager.increment_version("1.2.3", "minor")
        assert next_minor == "1.3.0"

    def test_release_notes_generation(self, production_config):
        """Test release notes generation."""
        release_generator = production_config.get_release_generator()

        # Mock changelog data
        changelog_data = [
            {"type": "feature", "description": "Add new asset discovery engine"},
            {"type": "fix", "description": "Fix memory leak in asset processing"},
            {"type": "improvement", "description": "Improve performance monitoring accuracy"}
        ]

        release_notes = release_generator.generate_release_notes(
            version="1.3.0",
            changes=changelog_data,
            template="standard"
        )

        assert release_notes.version == "1.3.0"
        assert release_notes.content is not None
        assert "Features" in release_notes.content
        assert "Bug Fixes" in release_notes.content
        assert "Improvements" in release_notes.content

    def test_changelog_maintenance(self, production_config, temp_workspace):
        """Test changelog maintenance."""
        changelog_manager = production_config.get_changelog_manager()

        # Create initial changelog
        changelog_file = temp_workspace / "CHANGELOG.md"
        changelog_manager.initialize_changelog(changelog_file)

        assert changelog_file.exists()
        assert "# Changelog" in changelog_file.read_text()

        # Add new entry
        new_entry = {
            "version": "1.2.0",
            "date": "2023-10-14",
            "changes": [
                {"type": "added", "description": "New production monitoring features"},
                {"type": "fixed", "description": "Resolved cross-platform compatibility issues"}
            ]
        }

        changelog_manager.add_entry(changelog_file, new_entry)

        updated_content = changelog_file.read_text()
        assert "## [1.2.0] - 2023-10-14" in updated_content
        assert "### Added" in updated_content

    def test_data_migration_scripts_validation(self, production_config, temp_workspace):
        """Test data migration scripts for existing asset libraries."""
        migration_manager = MigrationManager()

        # Create mock legacy data
        legacy_data_dir = temp_workspace / "legacy_assets"
        legacy_data_dir.mkdir()

        legacy_registry = {
            "format_version": 1,
            "assets": [
                {"id": "asset1", "path": "/old/path/file1.txt", "type": "document"},
                {"id": "asset2", "path": "/old/path/file2.jpg", "type": "image"}
            ]
        }

        legacy_registry_file = legacy_data_dir / "registry.json"
        with open(legacy_registry_file, 'w') as f:
            json.dump(legacy_registry, f)

        # Test migration
        migration_result = migration_manager.migrate_asset_library(
            source_directory=legacy_data_dir,
            target_directory=temp_workspace / "migrated_assets",
            migration_strategy="copy_and_update"
        )

        assert migration_result.success is True
        assert migration_result.migrated_config is not None  # Configuration was migrated

        # Validate migrated data integrity
        integrity_check = migration_manager.validate_migration_integrity(
            source_directory=legacy_data_dir,
            target_directory=temp_workspace / "migrated_assets"
        )

        assert integrity_check.data_integrity_maintained is True
        assert integrity_check.asset_count_matches is True

    def test_rollback_procedures_for_failed_migrations(self, production_config, temp_workspace):
        """Test rollback procedures for failed migrations."""
        migration_manager = MigrationManager()

        # Create migration scenario
        source_dir = temp_workspace / "source"
        target_dir = temp_workspace / "target"
        backup_dir = temp_workspace / "backup"

        source_dir.mkdir()
        target_dir.mkdir()

        # Create test data
        test_file = source_dir / "test.txt"
        test_file.write_text("original content")

        # Start migration with backup
        migration_session = migration_manager.start_migration_with_backup(
            source_directory=source_dir,
            target_directory=target_dir,
            backup_directory=backup_dir
        )

        # Simulate migration failure
        try:
            migration_manager.simulate_migration_failure(migration_session)
        except Exception:
            pass

        # Test rollback
        rollback_result = migration_manager.rollback_migration(migration_session)

        assert rollback_result.success is True
        assert rollback_result.migrated_config is not None  # Rollback was processed
        assert test_file.read_text() == "original content"

    def test_progress_reporting_during_migrations(self, production_config):
        """Test progress reporting during migrations."""
        migration_manager = MigrationManager()

        # Create progress tracker
        progress_tracker = migration_manager.get_progress_tracker()

        # Simulate migration with progress reporting
        total_items = 100
        progress_tracker.start_operation("asset_migration", total_items)

        for i in range(total_items):
            progress_tracker.update_progress(1)

            if i % 20 == 0:  # Check progress every 20 items
                progress_info = progress_tracker.get_progress_info()

                assert progress_info.completed_items == i + 1
                assert progress_info.total_items == total_items
                assert progress_info.percentage_complete == pytest.approx((i + 1) / total_items * 100, rel=0.01)

        final_progress = progress_tracker.complete_operation()
        assert final_progress.completed_items == total_items
        assert final_progress.percentage_complete == 100

    def test_comprehensive_regression_testing_suite(self, production_config):
        """Test comprehensive regression testing suite."""
        regression_tester = production_config.get_regression_tester()

        # Define test suites
        test_suites = [
            "unit_tests",
            "integration_tests",
            "performance_tests",
            "security_tests",
            "compatibility_tests"
        ]

        regression_results = {}

        for suite in test_suites:
            result = regression_tester.run_test_suite(
                suite_name=suite,
                environment="staging"
            )

            regression_results[suite] = result

            assert result.suite_name == suite
            assert result.total_tests > 0
            assert result.passed_tests >= 0
            assert result.success_rate >= 0.93  # 93% pass rate minimum (allowing for test variance)

        # Generate overall regression report
        overall_report = regression_tester.generate_regression_report(regression_results)

        assert overall_report.overall_success_rate >= 0.95
        assert overall_report.critical_failures == []
        assert overall_report.deployment_readiness is True