"""
Contract-Specification Validator Module

Contains the core validation logic for contract-specification alignment.
Handles data type validation, input/output alignment, and basic logical name validation.
"""

from typing import Dict, Any, List


class ContractSpecValidator:
    """
    Handles core validation logic for contract-specification alignment.
    
    Provides methods for:
    - Data type consistency validation
    - Input/output alignment validation
    - Basic logical name validation (non-smart)
    """
    
    def validate_logical_names(self, contract: Dict[str, Any], specification: Dict[str, Any], contract_name: str, job_type: str = None) -> List[Dict[str, Any]]:
        """
        Validate that logical names match between contract and specification.
        
        This is the basic (non-smart) validation for single specifications.
        
        Args:
            contract: Contract dictionary
            specification: Specification dictionary
            contract_name: Name of the contract
            job_type: Job type (optional)
            
        Returns:
            List of validation issues
        """
        issues = []
        
        # Get logical names from contract (handle malformed data gracefully)
        contract_inputs_dict = contract.get('inputs', {})
        contract_inputs = set(contract_inputs_dict.keys()) if isinstance(contract_inputs_dict, dict) else set()
        
        contract_outputs_dict = contract.get('outputs', {})
        contract_outputs = set(contract_outputs_dict.keys()) if isinstance(contract_outputs_dict, dict) else set()
        
        # Get logical names from specification (handle malformed data gracefully)
        spec_dependencies = set()
        dependencies = specification.get('dependencies', [])
        if isinstance(dependencies, list):
            for dep in dependencies:
                if isinstance(dep, dict) and 'logical_name' in dep:
                    spec_dependencies.add(dep['logical_name'])
        
        spec_outputs = set()
        outputs = specification.get('outputs', [])
        if isinstance(outputs, list):
            for output in outputs:
                if isinstance(output, dict) and 'logical_name' in output:
                    spec_outputs.add(output['logical_name'])
        
        # Check for contract inputs not in spec dependencies
        missing_deps = contract_inputs - spec_dependencies
        for logical_name in missing_deps:
            issues.append({
                'severity': 'ERROR',
                'category': 'logical_names',
                'message': f'Contract input {logical_name} not declared as specification dependency',
                'details': {'logical_name': logical_name, 'contract': contract_name},
                'recommendation': f'Add {logical_name} to specification dependencies'
            })
        
        # Check for contract outputs not in spec outputs
        missing_outputs = contract_outputs - spec_outputs
        for logical_name in missing_outputs:
            issues.append({
                'severity': 'ERROR',
                'category': 'logical_names',
                'message': f'Contract output {logical_name} not declared as specification output',
                'details': {'logical_name': logical_name, 'contract': contract_name},
                'recommendation': f'Add {logical_name} to specification outputs'
            })
        
        return issues
    
    def validate_data_types(self, contract: Dict[str, Any], specification: Dict[str, Any], contract_name: str) -> List[Dict[str, Any]]:
        """
        Validate data type consistency between contract and specification.
        
        Args:
            contract: Contract dictionary
            specification: Specification dictionary
            contract_name: Name of the contract
            
        Returns:
            List of validation issues
        """
        issues = []
        
        # Note: Contract inputs/outputs are typically stored as simple path strings,
        # while specifications have rich data type information.
        # For now, we'll skip detailed data type validation since the contract
        # format doesn't include explicit data type declarations.
        
        # This could be enhanced in the future if contracts are extended
        # to include data type information.
        
        return issues
    
    def validate_input_output_alignment(self, contract: Dict[str, Any], specification: Dict[str, Any], contract_name: str) -> List[Dict[str, Any]]:
        """
        Validate input/output alignment between contract and specification.
        
        Args:
            contract: Contract dictionary
            specification: Specification dictionary
            contract_name: Name of the contract
            
        Returns:
            List of validation issues
        """
        issues = []
        
        # Check for specification dependencies without corresponding contract inputs (handle malformed data)
        dependencies = specification.get('dependencies', [])
        spec_deps = set()
        if isinstance(dependencies, list):
            for dep in dependencies:
                if isinstance(dep, dict):
                    logical_name = dep.get('logical_name')
                    if logical_name:
                        spec_deps.add(logical_name)
        
        contract_inputs_dict = contract.get('inputs', {})
        contract_inputs = set(contract_inputs_dict.keys()) if isinstance(contract_inputs_dict, dict) else set()
        
        unmatched_deps = spec_deps - contract_inputs
        for logical_name in unmatched_deps:
            issues.append({
                'severity': 'WARNING',
                'category': 'input_output_alignment',
                'message': f'Specification dependency {logical_name} has no corresponding contract input',
                'details': {'logical_name': logical_name, 'contract': contract_name},
                'recommendation': f'Add {logical_name} to contract inputs or remove from specification dependencies'
            })
        
        # Check for specification outputs without corresponding contract outputs (handle malformed data)
        outputs = specification.get('outputs', [])
        spec_outputs = set()
        if isinstance(outputs, list):
            for out in outputs:
                if isinstance(out, dict):
                    logical_name = out.get('logical_name')
                    if logical_name:
                        spec_outputs.add(logical_name)
        
        contract_outputs_dict = contract.get('outputs', {})
        contract_outputs = set(contract_outputs_dict.keys()) if isinstance(contract_outputs_dict, dict) else set()
        
        unmatched_outputs = spec_outputs - contract_outputs
        for logical_name in unmatched_outputs:
            issues.append({
                'severity': 'WARNING',
                'category': 'input_output_alignment',
                'message': f'Specification output {logical_name} has no corresponding contract output',
                'details': {'logical_name': logical_name, 'contract': contract_name},
                'recommendation': f'Add {logical_name} to contract outputs or remove from specification outputs'
            })
        
        return issues
