"""
Application configuration .
"""

import logging
import os
from contextlib import contextmanager
from contextvars import ContextVar
from dataclasses import dataclass, replace
from typing import Any, Dict, Iterator, Optional

from semantic_models.logging_utils import summarize_for_logging

logger = logging.getLogger(__name__)


@dataclass
class AppConfig:
    """Application configuration."""

    dss_project_key: str

    semantic_model_id: Optional[str] = None

    term_extraction_llm_id: Optional[str] = None

    glossary_extraction_max_chunks: int = 20

    vocabulary_terms_in_prompt: int = 10

    # Record limits
    sources_records_limit: int = 50  # Max rows in sources (for LLM context)
    artifacts_records_limit: int = 1000  # Max rows in artifacts (for user export)

    # Agent configuration
    agent_recursion_limit: int = 100  # LangGraph max iterations
    max_rows_per_query: int = 1000  # Max rows returned per query
    glossary_autoload: bool = True  # Always auto-load glossary if LLM doesn't call get_glossary_terms


_config: Optional[AppConfig] = None
_config_override: ContextVar[Optional[AppConfig]] = ContextVar("app_config_override", default=None)


def _build_config(
    project_key: str,
    *,
    semantic_model_id: Optional[str] = None,
    term_extraction_llm_id: Optional[str] = None,
    glossary_extraction_max_chunks: int = 20,
    vocabulary_terms_in_prompt: int = 10,
    sources_records_limit: int = 50,
    artifacts_records_limit: int = 1000,
    agent_recursion_limit: int = 100,
    max_rows_per_query: int = 1000,
) -> AppConfig:
    return AppConfig(
        dss_project_key=project_key,
        semantic_model_id=semantic_model_id,
        term_extraction_llm_id=term_extraction_llm_id,
        glossary_extraction_max_chunks=glossary_extraction_max_chunks,
        vocabulary_terms_in_prompt=vocabulary_terms_in_prompt,
        sources_records_limit=sources_records_limit,
        artifacts_records_limit=artifacts_records_limit,
        agent_recursion_limit=agent_recursion_limit,
        max_rows_per_query=max_rows_per_query,
        glossary_autoload=True,
    )


def load_webapp_config() -> AppConfig:
    """
    Load configuration from DSS webapp context.
    """
    global _config

    import dataiku
    from dataiku.customwebapp import get_webapp_config

    client = dataiku.api_client()
    project = client.get_default_project()
    project_key = project.project_key

    webapp_config = get_webapp_config()

    logger.debug("Webapp configuration: %s", summarize_for_logging(webapp_config, max_chars=300, max_items=30))

    _config = _build_config(
        project_key,
        semantic_model_id=webapp_config["semanticModelId"],
        term_extraction_llm_id=webapp_config.get("term_extraction_llm_id"),
        glossary_extraction_max_chunks=int(webapp_config.get("glossary_extraction_max_chunks", 20)),
        vocabulary_terms_in_prompt=int(webapp_config.get("vocabulary_terms_in_prompt", 10)),
        sources_records_limit=int(webapp_config.get("sources_records_limit", 50)),
        artifacts_records_limit=int(webapp_config.get("artifacts_records_limit", 1000)),
        agent_recursion_limit=int(webapp_config.get("agent_recursion_limit", 100)),
        max_rows_per_query=int(webapp_config.get("max_rows_per_query", 1000)),
    )

    return _config


def load_tool_config(tool_config: Dict[str, Any]) -> AppConfig:
    """
    Load configuration from agent tool settings.
    """
    global _config

    import dataiku

    client = dataiku.api_client()

    # Use explicit project key if provided, otherwise use current project
    config_project_key = tool_config.get("project_key")
    if config_project_key:
        project = client.get_project(config_project_key)
    else:
        project = client.get_default_project()
    project_key = project.project_key

    llm_id = tool_config.get("llm_id")
    if not llm_id:
        raise ValueError("llm_id is required in tool config")

    _config = _build_config(
        project_key,
        semantic_model_id=tool_config.get("semantic_model_id"),
        term_extraction_llm_id=tool_config.get("term_extraction_llm_id") or llm_id,
        glossary_extraction_max_chunks=20,
        vocabulary_terms_in_prompt=int(tool_config.get("vocabulary_terms_in_prompt", 10)),
        sources_records_limit=int(tool_config.get("sources_records_limit", 50)),
        artifacts_records_limit=int(tool_config.get("artifacts_records_limit", 1000)),
        agent_recursion_limit=int(tool_config.get("agent_recursion_limit", 100)),
        max_rows_per_query=int(tool_config.get("max_rows_per_query", 1000)),
    )

    return _config


def load_local_config() -> AppConfig:
    """
    Load configuration from environment variables for local development.

    Only call this when LOCAL_DEV="true".

    Returns:
        Initialized AppConfig
    """
    global _config

    from dotenv import load_dotenv

    load_dotenv()

    project_key = os.getenv("DKU_CURRENT_PROJECT_KEY")
    if not project_key:
        raise ValueError("DKU_CURRENT_PROJECT_KEY env var required")

    _config = _build_config(
        project_key,
        term_extraction_llm_id=os.getenv("TERM_EXTRACTION_LLM_ID"),
        glossary_extraction_max_chunks=int(os.getenv("GLOSSARY_EXTRACTION_MAX_CHUNKS", "20")),
        vocabulary_terms_in_prompt=int(os.getenv("VOCABULARY_TERMS_IN_PROMPT", "10")),
        sources_records_limit=int(os.getenv("SOURCES_RECORDS_LIMIT", "50")),
        artifacts_records_limit=int(os.getenv("ARTIFACTS_RECORDS_LIMIT", "1000")),
        agent_recursion_limit=int(os.getenv("AGENT_RECURSION_LIMIT", "100")),
        max_rows_per_query=int(os.getenv("MAX_ROWS_PER_QUERY", "1000")),
    )

    return _config


def get_app_config() -> AppConfig:
    """Accessor.
    Config must be initialized first by calling the appropriate loader:
    - Webapp: load_webapp_config() in setup.py
    - Tool: load_tool_config() in tool.py set_config()
    - Local dev: load_local_config() at startup

    """
    override = _config_override.get()
    if override is not None:
        return override
    if _config is None:
        raise RuntimeError("AppConfig not initialized.")
    return _config


def set_app_config(config: AppConfig) -> None:
    """
    For testing or when you need to override the config.
    """
    global _config
    _config = config


@contextmanager
def override_app_config(**overrides: Any) -> Iterator[AppConfig]:
    if _config is None:
        raise RuntimeError("AppConfig not initialized.")
    base = _config
    merged = replace(base, **overrides)
    token = _config_override.set(merged)
    try:
        yield merged
    finally:
        _config_override.reset(token)
