"""SDK configuration dataclass."""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Callable


@dataclass
class AutoPromptLabConfig:
    """Configuration for AutoPromptLab SDK.
    
    Required parameters are listed first (no defaults).
    Optional parameters follow with sensible defaults.
    """
    
    # ========================================
    # Required - Local Environment (2 params)
    # ========================================

    braintrust_api_key: str
    """Braintrust API key for evaluation tracking (required)."""
    
    # ========================================
    # Required - Experiment Config (3 params)
    # ========================================
    
    dataset_name: str
    """Dataset name for evaluation, e.g. picasso_cn_chat_0923 (required)."""
    
    picasso_branch: str
    """Picasso repository branch for prompts (required)."""
    
    liquid_prompt_entries: list[dict]
    """List of liquid template entries with path and can_edit flag (required)."""
    
    # ========================================
    # Optional - Storage
    # ========================================
    
    session_dir: Path = field(default_factory=lambda: Path(".autopromptlab/sessions"))
    """Root directory for the current session. Checkpoints, outputs, and logs
    are stored directly under session_dir:
    session_dir/
    ├── checkpoints/     # State snapshots
    ├── outputs/         # Intermediate outputs (prompts, state)
    └── logs/            # Optional run logs when enable_run_logging=True
    """
    
    # ========================================
    # Optional - Braintrust
    # ========================================
    
    braintrust_org: str = "non-pme"
    """Braintrust organization (non-pme or bt-azure)."""
    
    eval_name: str = "default"
    """Name for the evaluation run."""
    
    eval_project_name: str = ""
    """Braintrust project name for evaluation."""
    
    dataset_project_name: str = ""
    """Braintrust dataset project name."""

    dimension_threshold: float = 0.5
    """Threshold for low-score dimension filtering in Braintrust analysis."""

    bad_case_limit_per_iteration: int = 10
    """Max bad cases to analyze per iteration."""

    badcase_deep_analysis: bool = False
    """When True, get_low_case_details automatically runs skill-guided per-case root cause
    analysis (include_analysis=True by default).
    Requires analysis_agent_client to be configured. Defaults to False."""

    metrics_config: list[dict[str, Any]] | None = None
    """Metric configuration list.

    UI-compatible fields per item:
    - name (required)
    - is_llm_judged (optional, default True)
    - description (optional)
    - measurement_purpose (optional)
    - optimization_direction (optional: higher_better/lower_better)
    If omitted, SDK may derive defaults from dataset mapping.
    """
    
    # ========================================
    # Optional - Aipa settings
    # ========================================
    
    max_dataset_rows: int = 300
    """Maximum dataset rows for evaluation."""

    dataset_sampling_method: str = "first"
    """Dataset sampling method: all, first, last, or custom."""

    additional_cmd_args: str = ""
    """Additional arguments appended to the eval runner command."""

    conversation_mode: str = "Smart"
    """Conversation mode (Smart, DefaultMode, etc.)."""

    environment: str = "global"
    """Evaluation environment (global/china)."""

    model: str | None = None
    """Aipa eval model parameter."""

    picasso_env: str = "runner"
    """Picasso evaluation environment passed as -PicassoEnv to the eval script (runner/custom)."""

    task_id_prefix: str = ""
    """Optional task ID prefix. When set, task_id = prefix + run_id + commit_id_short."""
    
    # ========================================
    # Optional - Picasso Git settings
    # ========================================
    
    picasso_commit_id: str | None = None
    """Picasso commit ID to reset to."""
    
    # ========================================
    # Optional - Feature flags
    # ========================================
    
    add_feature_flags: str = ""
    """Additional feature flags to enable."""
    
    baseline_feature_flags: str = ""
    """Baseline feature flags."""
    
    picasso_version: str = "Baseline"
    """Picasso version identifier."""

    run_leaderboard_after_optimization: bool = False
    """Whether to submit leaderboard job after optimization completes."""

    # ========================================
    # Optional - Optimization defaults
    # ========================================

    max_rounds: int = 10
    """Default max rounds used by optimize()/resume() when not explicitly passed."""

    termination_rule: dict[str, Any] | None = None
    """Default termination rule for optimize(), e.g. {'type': 'no_progress', 'rounds': 3}."""

    rollback_strategy: str | None = None
    """Default rollback strategy passed into user_input."""

    baseline_experiment_id: str | None = None
    """Default baseline experiment id injected into user_input for optimize()."""

    baseline_experiment_link: str | None = None
    """Default baseline experiment link injected into user_input for optimize()."""

    selection_strategy: str | None = None
    """Selection strategy: 'greedy' or 'gepa'. None means server default."""

    pareto_max_selected: int | None = None
    """Max candidates from Pareto front (1-5). Only used when selection_strategy='gepa'."""
    
    # ========================================
    # Optional - Model settings
    # ========================================

    model_client_type: str = "Azure"
    """Model client type: Azure, Papyrus, Local."""

    azure_endpoint: str | None = None
    """Azure OpenAI endpoint URL."""

    model_deployment: str | None = None
    """Azure OpenAI model deployment name."""

    azure_api_version: str | None = None
    """Azure OpenAI API version."""

    papyrus_endpoint: str | None = None
    """Papyrus endpoint URL."""

    papyrus_model: str | None = None
    """Papyrus model name."""

    papyrus_quota_id: str | None = None
    """Papyrus quota ID for authentication."""

    papyrus_scope: str | None = None
    """Papyrus auth scope for token generation."""

    local_endpoint: str = "http://localhost:23333/api/openai/v1"
    """Local OpenAI-compatible base URL."""

    local_model: str = ""
    """Local model ID (required when model_client_type=Local)."""

    use_structured_output: bool = True
    """Whether to use structured output for model responses."""

    # ========================================
    # Optional - User input proxy
    # ========================================

    user_proxy_mode: str | None = None
    """User proxy mode override: web/console/callback. None means SDK default selection."""

    user_proxy_timeout: float = 3600.0
    """Timeout (seconds) waiting for user input in UserProxy."""

    prefer_native_user_proxy: bool = False
    """Whether to prefer AutoGen native UserProxyAgent when constructor is compatible."""

    user_input_callback: Callable[..., Any] | None = None
    """Optional callback for callback-mode user input."""
    
    # ========================================
    # Optional - Debug
    # ========================================
    
    local_debug: bool = False
    """Enable local debug mode."""

    enable_run_logging: bool = False
    """Whether optimize()/resume() should create per-run log files under session_dir/logs."""
    
    log_level: int = logging.INFO
    """Logging level for SDK operations."""
