"""
Configuration management for SLTK.

Provides centralized path configuration for datasets, annotations,
and features with environment variable support.

All paths can be configured via environment variables:
    SLTK_RESEARCH_DATA_ROOT - Base path for research data (default: /vol/research)
    SLTK_FEATURE_POOL_ROOT - Base path for feature pool (default: /vol/research/SignFeaturePool)
    SLTK_DATASETS_ROOT - Base path for datasets (default: /vol/research/datasets)
    SLTK_ANNOTATION_ROOT - Path to unified annotations
    SLTK_VIDEO_ROOT - Override for video root
    SLTK_FEATURE_ROOT - Path to extracted features
    SLTK_DATASET_ROOT - General dataset root override
    SLTK_NLF_MODEL_PATH - Path to NLF model weights
    SLTK_WILOR_MODEL_PATH - Path to WiLoR model weights
    SLTK_SIGNREP_ROOT - Path to SignRep installation
    SLTK_SIGNREP_CHECKPOINT - Path to SignRep checkpoint
    SLTK_IK_SOLVER_ROOT - Path to IK solver installation
    SLTK_SEGMENTOR_PATH - Path to segmentor model checkpoint
"""

from __future__ import annotations

import os
import threading
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

# Environment variable names
ENV_ANNOTATION_ROOT = "SLTK_ANNOTATION_ROOT"
ENV_VIDEO_ROOT = "SLTK_VIDEO_ROOT"
ENV_FEATURE_ROOT = "SLTK_FEATURE_ROOT"
ENV_DATASET_ROOT = "SLTK_DATASET_ROOT"

# New environment variables for configurable paths
ENV_RESEARCH_DATA_ROOT = "SLTK_RESEARCH_DATA_ROOT"
ENV_FEATURE_POOL_ROOT = "SLTK_FEATURE_POOL_ROOT"
ENV_DATASETS_ROOT = "SLTK_DATASETS_ROOT"
ENV_NLF_MODEL_PATH = "SLTK_NLF_MODEL_PATH"
ENV_WILOR_MODEL_PATH = "SLTK_WILOR_MODEL_PATH"
ENV_SIGNREP_ROOT = "SLTK_SIGNREP_ROOT"
ENV_SIGNREP_CHECKPOINT = "SLTK_SIGNREP_CHECKPOINT"
ENV_IK_SOLVER_ROOT = "SLTK_IK_SOLVER_ROOT"
ENV_SEGMENTOR_PATH = "SLTK_SEGMENTOR_PATH"
ENV_NLF_ROOT = "SLTK_NLF_ROOT"


def _get_research_data_root() -> Path:
    """Get the research data root from environment or default."""
    return Path(os.environ.get(ENV_RESEARCH_DATA_ROOT, "/vol/research"))


def _get_datasets_root() -> Path:
    """Get the datasets root from environment or default."""
    env_val = os.environ.get(ENV_DATASETS_ROOT)
    if env_val:
        return Path(env_val)
    return _get_research_data_root() / "datasets"


def _get_feature_pool_root() -> Path:
    """Get the feature pool root from environment or default."""
    env_val = os.environ.get(ENV_FEATURE_POOL_ROOT)
    if env_val:
        return Path(env_val)
    return _get_research_data_root() / "SignFeaturePool"


# Default paths for research network (computed from environment)
def get_default_dataset_roots() -> dict[str, Path]:
    """Get default dataset root paths, configurable via environment."""
    datasets_root = _get_datasets_root()
    return {
        "singlevideo": datasets_root / "singlevideo",
        "multiview": datasets_root / "multiview",
        "mixedmode": datasets_root / "mixedmode",
    }


# Legacy compatibility - these are computed at import time
# but will respect environment variables if set
DEFAULT_DATASET_ROOTS = get_default_dataset_roots()

DEFAULT_FEATURE_ROOT = _get_feature_pool_root() / "features2"


# Dataset-specific paths on research network
# BSLCP uses custom paths from scratch storage
_BSLCP_ROOT = Path(
    os.environ.get("SLTK_BSLCP_ROOT", "/mnt/fast/nobackup/scratch4weeks/ef0036/videos/bslcp/BSLCP")
)
_BSLCP2_ROOT = Path(
    os.environ.get(
        "SLTK_BSLCP2_ROOT", "/mnt/fast/nobackup/scratch4weeks/ef0036/videos/BSLCP2/BSLCP"
    )
)

DATASET_PATHS: dict[str, dict[str, Any]] = {
    "bslcp": {
        "root": _BSLCP_ROOT,
        "annotation_format": "elan",
        "language": "bsl",
    },
    "bslcp2": {
        "root": _BSLCP2_ROOT,
        "annotation_format": "elan",
        "language": "bsl",
    },
    "bobsl": {
        "root": DEFAULT_DATASET_ROOTS["mixedmode"] / "BOBSL",
        "annotation_format": "bobsl",  # TSV + pickle + VTT
        "language": "bsl",
    },
    "how2sign": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "how2sign",
        "annotation_format": "csv",
        "language": "asl",
    },
    "how2signvids": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "how2signvids",
        "annotation_format": "csv",
        "language": "asl",
    },
    "asl_citizen": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "ASL_Citizen",
        "annotation_format": "csv",
        "language": "asl",
    },
    "asldict": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "asldict",
        "annotation_format": "asldict_json",
        "language": "asl",
    },
    "bsldict": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "bsldict",
        "annotation_format": "asldict_json",  # Same format as asldict
        "language": "bsl",
    },
    "ms_asl": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "ms-asl",
        "annotation_format": "msasl_json",
        "language": "asl",
    },
    "wlasl": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "wlasl2",
        "annotation_format": "wlasl_json",
        "language": "asl",
    },
    "wlasl0": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "wlasl0",
        "annotation_format": "wlasl_json",
        "language": "asl",
    },
    "wlasl1": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "wlasl1",
        "annotation_format": "wlasl_json",
        "language": "asl",
    },
    "wlasl2": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "wlasl2",
        "annotation_format": "wlasl_json",
        "language": "asl",
    },
    "yt_asl": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "YouTube-ASL",
        "annotation_format": "vtt",
        "language": "asl",
    },
    "ytsl_25": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "ytsl-25",
        "annotation_format": "tsv",
        "language": "mixed",
    },
    "bslzone": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "bslzone",
        "annotation_format": "bslzone",  # VTT + text scenes
        "language": "bsl",
    },
    "csl_daily": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "csl-daily",
        "annotation_format": "csl_daily_json",
        "language": "csl",
    },
    "cslnews": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "cslnews",
        "annotation_format": "csl_daily_json",
        "language": "csl",
    },
    "phoenix": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "phoenix",
        "annotation_format": "phoenix_csv",
        "language": "dgs",
    },
    "rachel": {
        "root": DEFAULT_DATASET_ROOTS["singlevideo"] / "rachel",
        "annotation_format": "csv",
        "language": "bsl",
    },
}


@dataclass
class SLTKConfig:
    """
    Configuration container for SLTK paths and settings.

    Reads from environment variables with fallback to defaults.

    Example:
        >>> config = SLTKConfig()
        >>> print(config.annotation_root)
        PosixPath('/home/user/Projects/VLT/sltk/data/annotations/v1.0')

        >>> # Override via environment
        >>> import os
        >>> os.environ['SLTK_ANNOTATION_ROOT'] = '/custom/path'
        >>> config = SLTKConfig()
        >>> print(config.annotation_root)
        PosixPath('/custom/path')
    """

    # Default annotation root is in the SLTK package
    _default_annotation_root: Path = field(
        default_factory=lambda: Path(__file__).parent / "data" / "annotations" / "v1.0"
    )

    @property
    def annotation_root(self) -> Path:
        """Root directory for unified annotation files."""
        env_path = os.environ.get(ENV_ANNOTATION_ROOT)
        if env_path:
            return Path(env_path)
        return self._default_annotation_root

    @property
    def video_root(self) -> Path | None:
        """Root directory for video files (if overridden)."""
        env_path = os.environ.get(ENV_VIDEO_ROOT)
        if env_path:
            return Path(env_path)
        return None

    @property
    def feature_root(self) -> Path:
        """Root directory for pre-extracted features."""
        env_path = os.environ.get(ENV_FEATURE_ROOT)
        if env_path:
            return Path(env_path)
        return DEFAULT_FEATURE_ROOT

    @property
    def dataset_root(self) -> Path | None:
        """General dataset root (if overridden)."""
        env_path = os.environ.get(ENV_DATASET_ROOT)
        if env_path:
            return Path(env_path)
        return None

    def get_dataset_path(self, dataset: str) -> Path | None:
        """
        Get the root path for a specific dataset.

        Args:
            dataset: Dataset name (e.g., 'bslcp', 'wlasl')

        Returns:
            Path to dataset root, or None if not found
        """
        dataset = dataset.lower().replace("-", "_")

        # Check environment override first
        if self.dataset_root:
            return self.dataset_root / dataset

        # Look up in known paths
        if dataset in DATASET_PATHS:
            return DATASET_PATHS[dataset]["root"]

        return None

    def get_dataset_info(self, dataset: str) -> dict[str, Any] | None:
        """
        Get configuration info for a specific dataset.

        Args:
            dataset: Dataset name

        Returns:
            Dictionary with root, annotation_format, language, etc.
        """
        dataset = dataset.lower().replace("-", "_")
        return DATASET_PATHS.get(dataset)

    def get_annotation_path(self, dataset: str) -> Path:
        """
        Get the unified annotation directory for a dataset.

        Args:
            dataset: Dataset name

        Returns:
            Path to dataset's unified annotation directory
        """
        dataset = dataset.lower().replace("-", "_")
        return self.annotation_root / dataset

    def get_feature_path(self, dataset: str, format: str = "wilor") -> Path:
        """
        Get the feature directory for a dataset and format.

        Args:
            dataset: Dataset name
            format: Feature format ('wilor', 'smpl', etc.)

        Returns:
            Path to features directory
        """
        dataset = dataset.lower().replace("-", "_")
        return self.feature_root / dataset / format

    def list_datasets(self) -> list:
        """List all known dataset names."""
        return list(DATASET_PATHS.keys())

    def list_datasets_by_language(self, language: str) -> list:
        """
        List datasets for a specific sign language.

        Args:
            language: Language code ('asl', 'bsl', 'csl', 'dgs', etc.)

        Returns:
            List of dataset names
        """
        return [
            name for name, info in DATASET_PATHS.items() if info.get("language") == language.lower()
        ]

    def list_datasets_by_format(self, annotation_format: str) -> list:
        """
        List datasets using a specific annotation format.

        Args:
            annotation_format: Format name ('elan', 'csv', 'wlasl_json', etc.)

        Returns:
            List of dataset names
        """
        return [
            name
            for name, info in DATASET_PATHS.items()
            if info.get("annotation_format") == annotation_format.lower()
        ]


# Global config instance
_config: SLTKConfig | None = None
_config_lock = threading.Lock()


def get_config() -> SLTKConfig:
    """
    Get the global SLTK configuration.

    Creates the config instance on first call.
    Thread-safe using double-checked locking pattern.

    Returns:
        SLTKConfig instance
    """
    global _config
    if _config is None:
        with _config_lock:
            # Double-check after acquiring lock
            if _config is None:
                _config = SLTKConfig()
    return _config


def reset_config():
    """Reset the global configuration (useful for testing)."""
    global _config
    with _config_lock:
        _config = None


# ============================================================================
# Model Path Helpers
# ============================================================================


def get_nlf_model_path() -> Path | None:
    """Get the NLF model path from environment."""
    env_val = os.environ.get(ENV_NLF_MODEL_PATH)
    if env_val:
        return Path(env_val)
    return None


def get_wilor_model_path() -> Path | None:
    """Get the WiLoR model path from environment."""
    env_val = os.environ.get(ENV_WILOR_MODEL_PATH)
    if env_val:
        return Path(env_val)
    return None


def get_signrep_root() -> Path | None:
    """Get the SignRep installation root from environment."""
    env_val = os.environ.get(ENV_SIGNREP_ROOT)
    if env_val:
        return Path(env_val)
    return None


def get_signrep_checkpoint() -> Path | None:
    """Get the SignRep checkpoint path from environment."""
    env_val = os.environ.get(ENV_SIGNREP_CHECKPOINT)
    if env_val:
        return Path(env_val)
    return None


def get_ik_solver_root() -> Path | None:
    """Get the IK solver installation root from environment."""
    env_val = os.environ.get(ENV_IK_SOLVER_ROOT)
    if env_val:
        return Path(env_val)
    return None


def get_segmentor_path() -> Path | None:
    """Get the segmentor model checkpoint path from environment."""
    env_val = os.environ.get(ENV_SEGMENTOR_PATH)
    if env_val:
        return Path(env_val)
    return None


def get_nlf_root() -> Path | None:
    """Get the NLF installation root from environment."""
    env_val = os.environ.get(ENV_NLF_ROOT)
    if env_val:
        return Path(env_val)
    return None
