"""Configuration management system for email-sorter."""
import os
import yaml
import logging
from pathlib import Path
from typing import Dict, Any, Optional
from pydantic import BaseModel, Field

logger = logging.getLogger(__name__)


class CalibrationConfig(BaseModel):
    """Calibration phase configuration."""
    sample_size: int = 1500
    sample_strategy: str = "stratified"
    validation_size: int = 300
    min_confidence: float = 0.6


class ProcessingConfig(BaseModel):
    """Processing pipeline configuration."""
    batch_size: int = 100
    llm_queue_size: int = 100
    parallel_workers: int = 4
    checkpoint_interval: int = 1000
    checkpoint_dir: str = "checkpoints"


class ClassificationConfig(BaseModel):
    """Classification configuration."""
    default_threshold: float = 0.75
    min_threshold: float = 0.60
    max_threshold: float = 0.90
    adjustment_step: float = 0.05
    adjustment_frequency: int = 1000
    category_thresholds: Dict[str, float] = Field(default_factory=dict)


class OllamaConfig(BaseModel):
    """Ollama LLM provider configuration."""
    base_url: str = "http://localhost:11434"
    calibration_model: str = "qwen3:1.7b"  # Changed from 4b to 1.7b for speed testing
    consolidation_model: str = "qwen3:8b-q4_K_M"  # Larger model for structured JSON output
    classification_model: str = "qwen3:1.7b"
    temperature: float = 0.1
    max_tokens: int = 500
    timeout: int = 30
    retry_attempts: int = 3


class OpenAIConfig(BaseModel):
    """OpenAI API configuration."""
    base_url: str = "https://api.openai.com/v1"
    api_key: Optional[str] = None
    calibration_model: str = "gpt-4o-mini"
    classification_model: str = "gpt-4o-mini"
    temperature: float = 0.1
    max_tokens: int = 500


class LLMConfig(BaseModel):
    """LLM provider configuration."""
    provider: str = "ollama"  # ollama or openai
    ollama: OllamaConfig = Field(default_factory=OllamaConfig)
    openai: OpenAIConfig = Field(default_factory=OpenAIConfig)
    fallback_enabled: bool = True


class EmailProvidersConfig(BaseModel):
    """Email provider configurations."""
    gmail: Dict[str, Any] = Field(default_factory=lambda: {"batch_size": 100})
    microsoft: Dict[str, Any] = Field(default_factory=lambda: {"batch_size": 100})
    imap: Dict[str, Any] = Field(default_factory=lambda: {"timeout": 30, "batch_size": 50})


class FeaturesConfig(BaseModel):
    """Feature extraction configuration."""
    text_features: Dict[str, Any] = Field(
        default_factory=lambda: {
            "max_vocab_size": 10000,
            "ngram_range": [1, 2],
            "min_df": 2,
            "max_df": 0.95,
        }
    )
    embedding_model: str = "all-MiniLM-L6-v2"
    embedding_batch_size: int = 32


class ExportConfig(BaseModel):
    """Export configuration."""
    format: str = "json"
    include_confidence: bool = True
    create_report: bool = True
    output_dir: str = "results"


class LoggingConfig(BaseModel):
    """Logging configuration."""
    level: str = "INFO"
    file: str = "logs/email-sorter.log"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"


class CleanupConfig(BaseModel):
    """Cleanup configuration."""
    delete_temp_files: bool = True
    delete_repo_after: bool = False
    temp_dir: str = ".email-sorter-tmp"


class Config(BaseModel):
    """Main configuration model."""
    version: str = "1.0.0"
    calibration: CalibrationConfig = Field(default_factory=CalibrationConfig)
    processing: ProcessingConfig = Field(default_factory=ProcessingConfig)
    classification: ClassificationConfig = Field(default_factory=ClassificationConfig)
    llm: LLMConfig = Field(default_factory=LLMConfig)
    email_providers: EmailProvidersConfig = Field(default_factory=EmailProvidersConfig)
    features: FeaturesConfig = Field(default_factory=FeaturesConfig)
    export: ExportConfig = Field(default_factory=ExportConfig)
    logging: LoggingConfig = Field(default_factory=LoggingConfig)
    cleanup: CleanupConfig = Field(default_factory=CleanupConfig)

    class Config:
        extra = "allow"

    @classmethod
    def from_yaml(cls, config_path: str) -> "Config":
        """Load configuration from YAML file."""
        if not os.path.exists(config_path):
            logger.warning(f"Config file not found: {config_path}, using defaults")
            return cls()

        try:
            with open(config_path, 'r') as f:
                config_dict = yaml.safe_load(f) or {}
            return cls(**config_dict)
        except Exception as e:
            logger.error(f"Error loading config from {config_path}: {e}")
            return cls()

    def to_yaml(self, output_path: str) -> None:
        """Save configuration to YAML file."""
        Path(output_path).parent.mkdir(parents=True, exist_ok=True)
        with open(output_path, 'w') as f:
            yaml.dump(self.dict(), f, default_flow_style=False)


def load_config(config_path: Optional[str] = None) -> Config:
    """Load configuration from file or use defaults."""
    if config_path is None:
        # Try common locations
        for path in ["config/default_config.yaml", "config/config.yaml", ".env"]:
            if os.path.exists(path):
                config_path = path
                break

    if config_path:
        return Config.from_yaml(config_path)
    else:
        logger.info("No config file found, using default configuration")
        return Config()


def load_categories(categories_path: str = "config/categories.yaml") -> Dict[str, Dict]:
    """Load category definitions from YAML."""
    if not os.path.exists(categories_path):
        logger.warning(f"Categories file not found: {categories_path}")
        return {}

    try:
        with open(categories_path, 'r') as f:
            data = yaml.safe_load(f) or {}
        return data.get('categories', {})
    except Exception as e:
        logger.error(f"Error loading categories: {e}")
        return {}


def load_features(features_path: str = "config/features.yaml") -> Dict[str, Any]:
    """Load feature configuration from YAML."""
    if not os.path.exists(features_path):
        logger.warning(f"Features file not found: {features_path}")
        return {}

    try:
        with open(features_path, 'r') as f:
            return yaml.safe_load(f) or {}
    except Exception as e:
        logger.error(f"Error loading features: {e}")
        return {}
