"""
Schema Contract

Standard schema definitions for data validation.
"""

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Union
from enum import Enum


class SchemaType(str, Enum):
    """Schema field types."""
    
    STRING = "string"
    INTEGER = "integer"
    FLOAT = "float"
    BOOLEAN = "boolean"
    DATE = "date"
    DATETIME = "datetime"
    ARRAY = "array"
    OBJECT = "object"
    UUID = "uuid"
    EMAIL = "email"
    URL = "url"
    PHONE = "phone"


@dataclass
class SchemaField:
    """
    Schema field definition.
    
    Defines validation rules for a single field.
    """
    
    name: str
    type: SchemaType
    required: bool = True
    nullable: bool = False
    default: Any = None
    min_length: Optional[int] = None
    max_length: Optional[int] = None
    min_value: Optional[Union[int, float]] = None
    max_value: Optional[Union[int, float]] = None
    pattern: Optional[str] = None  # Regex pattern
    enum_values: Optional[List[Any]] = None
    description: Optional[str] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        result = {
            "name": self.name,
            "type": self.type.value,
            "required": self.required,
            "nullable": self.nullable,
        }
        
        if self.default is not None:
            result["default"] = self.default
        if self.min_length is not None:
            result["minLength"] = self.min_length
        if self.max_length is not None:
            result["maxLength"] = self.max_length
        if self.min_value is not None:
            result["minimum"] = self.min_value
        if self.max_value is not None:
            result["maximum"] = self.max_value
        if self.pattern:
            result["pattern"] = self.pattern
        if self.enum_values:
            result["enum"] = self.enum_values
        if self.description:
            result["description"] = self.description
        
        return result


@dataclass
class Schema:
    """
    Schema definition for data validation.
    
    Represents the structure and validation rules for a data object.
    """
    
    name: str
    version: str = "1.0"
    description: Optional[str] = None
    fields: List[SchemaField] = field(default_factory=list)
    
    def get_field(self, name: str) -> Optional[SchemaField]:
        """Get field by name."""
        for f in self.fields:
            if f.name == name:
                return f
        return None
    
    def add_field(self, schema_field: SchemaField) -> None:
        """Add a field to the schema."""
        if self.get_field(schema_field.name):
            raise ValueError(f"Field {schema_field.name} already exists")
        self.fields.append(schema_field)
    
    def required_fields(self) -> List[str]:
        """Get list of required field names."""
        return [f.name for f in self.fields if f.required]
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        return {
            "name": self.name,
            "version": self.version,
            "description": self.description,
            "fields": [f.to_dict() for f in self.fields],
        }
    
    def to_json_schema(self) -> Dict[str, Any]:
        """Convert to JSON Schema format."""
        properties = {}
        required = []
        
        for f in self.fields:
            prop = {"type": self._map_type(f.type)}
            
            if f.min_length is not None:
                prop["minLength"] = f.min_length
            if f.max_length is not None:
                prop["maxLength"] = f.max_length
            if f.min_value is not None:
                prop["minimum"] = f.min_value
            if f.max_value is not None:
                prop["maximum"] = f.max_value
            if f.pattern:
                prop["pattern"] = f.pattern
            if f.enum_values:
                prop["enum"] = f.enum_values
            if f.description:
                prop["description"] = f.description
            
            properties[f.name] = prop
            
            if f.required:
                required.append(f.name)
        
        return {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "title": self.name,
            "description": self.description,
            "type": "object",
            "properties": properties,
            "required": required,
        }
    
    def _map_type(self, schema_type: SchemaType) -> str:
        """Map schema type to JSON Schema type."""
        mapping = {
            SchemaType.STRING: "string",
            SchemaType.INTEGER: "integer",
            SchemaType.FLOAT: "number",
            SchemaType.BOOLEAN: "boolean",
            SchemaType.DATE: "string",
            SchemaType.DATETIME: "string",
            SchemaType.ARRAY: "array",
            SchemaType.OBJECT: "object",
            SchemaType.UUID: "string",
            SchemaType.EMAIL: "string",
            SchemaType.URL: "string",
            SchemaType.PHONE: "string",
        }
        return mapping.get(schema_type, "string")
