"""Core data models for MOSAICX."""

import json
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

from pydantic import BaseModel, Field


class FieldDefinition(BaseModel):
    """Definition of an extraction field."""
    field: str
    type: str  # string, integer, float, date, boolean, array
    description: str
    required: bool = False
    validation: Optional[Dict[str, Any]] = None


class SchemaDefinition(BaseModel):
    """Schema definition for extraction."""
    findings: List[FieldDefinition]


class OutputConfig(BaseModel):
    """Output configuration."""
    format: str = "json"
    include_confidence: bool = True
    include_source_text: bool = False
    confidence_threshold: float = 0.7


class LLMConfig(BaseModel):
    """LLM configuration."""
    model: str = "llama2"
    temperature: float = 0.1
    max_tokens: int = 1000
    ollama_url: str = "http://localhost:11434"


class ValidationConfig(BaseModel):
    """Validation configuration."""
    required_fields: List[str] = []


"""Core data models for MOSAICX."""

import json
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional, Union

from pydantic import BaseModel, Field


class FieldDefinition(BaseModel):
    """Definition of an extraction field."""
    field: str
    type: str  # string, integer, float, date, boolean, array
    description: str
    required: bool = False
    validation: Optional[Dict[str, Any]] = None


class SchemaDefinition(BaseModel):
    """Schema definition for extraction."""
    findings: List[FieldDefinition]


class OutputConfig(BaseModel):
    """Output configuration."""
    format: str = "json"
    include_confidence: bool = True
    include_source_text: bool = False
    confidence_threshold: float = 0.7


class LLMConfig(BaseModel):
    """LLM configuration."""
    model: str = "llama2"
    temperature: float = 0.1
    max_tokens: int = 1000
    ollama_url: str = "http://localhost:11434"


class ValidationConfig(BaseModel):
    """Validation configuration."""
    required_fields: List[str] = []


class ExtractionConfig(BaseModel):
    """Complete extraction configuration."""
    # Use a different field name internally to avoid BaseModel.schema() conflict
    extraction_schema: Union[SchemaDefinition, Dict[str, Any]]
    output: Optional[OutputConfig] = None
    llm: Optional[LLMConfig] = None
    validation: Optional[ValidationConfig] = None
    
    # Additional fields for simple format compatibility
    required_fields: List[str] = Field(default_factory=list)
    output_format: str = "json"
    validation_enabled: bool = True
    max_retries: int = 3
    expected_date_format: Optional[str] = None
    validation_patterns: Optional[Dict[str, str]] = None
    
    # Property for backward compatibility
    @property
    def schema(self) -> Union[SchemaDefinition, Dict[str, Any]]:
        """Get the extraction schema (backward compatibility)."""
        return self.extraction_schema
    
    @schema.setter
    def schema(self, value: Union[SchemaDefinition, Dict[str, Any]]) -> None:
        """Set the extraction schema (backward compatibility)."""
        self.extraction_schema = value
    
    @classmethod
    def from_dict(cls, config_dict: Dict[str, Any]) -> "ExtractionConfig":
        """Create configuration from dictionary."""
        # Handle 'schema' key in input for backward compatibility
        if 'schema' in config_dict:
            config_dict = config_dict.copy()
            config_dict['extraction_schema'] = config_dict.pop('schema')
        return cls(**config_dict)

    @classmethod
    def from_file(cls, config_path: Union[str, Path]) -> "ExtractionConfig":
        """Load configuration from YAML or JSON file."""
        path = Path(config_path)
        if not path.exists():
            from ..exceptions import ConfigurationError
            raise ConfigurationError(f"Configuration file not found: {config_path}")
        
        try:
            with open(path, 'r') as f:
                if path.suffix.lower() in ['.yml', '.yaml']:
                    import yaml
                    config_dict = yaml.safe_load(f)
                else:
                    config_dict = json.load(f)
            return cls.from_dict(config_dict)
        except Exception as e:
            from ..exceptions import ConfigurationError
            raise ConfigurationError(f"Error loading configuration: {e}")


class AnalysisConfig(BaseModel):
    """Configuration for patient analysis."""
    type: str = "patient_timeline"
    patient_identification: List[str] = ["patient_name", "mrn"]
    timeline_analysis: Dict[str, Any] = {}
    synthesis: Dict[str, Any] = {}


class ExtractionResult(BaseModel):
    """Result of report extraction."""
    extracted_data: Dict[str, Any]
    confidence_scores: Dict[str, float] = {}
    metadata: Dict[str, Any] = {}
    processing_time: float = 0.0
    model_info: Dict[str, Any] = {}
    source_file: Optional[str] = None

    def to_json(self) -> str:
        """Convert result to JSON string."""
        return self.model_dump_json(indent=2)

    def to_dict(self) -> Dict[str, Any]:
        """Convert result to dictionary."""
        return self.model_dump()

    def get_high_confidence_fields(self, threshold: float = 0.8) -> Dict[str, Any]:
        """Get fields that meet confidence threshold."""
        return {
            field: value 
            for field, value in self.extracted_data.items()
            if self.confidence_scores.get(field, 0.0) >= threshold
        }


class AnalysisResult(BaseModel):
    """Result of patient analysis."""
    patient_timeline: List[Dict[str, Any]] = []
    synthesis: Dict[str, Any] = {}
    key_events: List[str] = []
    metadata: Dict[str, Any] = {}

    def to_json(self) -> str:
        """Convert result to JSON string."""
        return self.model_dump_json(indent=2)

    def to_dict(self) -> Dict[str, Any]:
        """Convert result to dictionary."""
        return self.model_dump()
