"""Configuration validation logic."""

from pathlib import Path
from typing import Any, Dict, List

from src.core.constants import TIMEFRAMES
from src.core.exceptions import ConfigurationError, ValidationError


def validate_config(config: Dict[str, Any]) -> None:
    """
    Validate configuration dictionary.

    Args:
        config: Configuration dictionary

    Raises:
        ConfigurationError: If configuration is invalid
    """
    # Validate app config
    if "app" not in config:
        raise ConfigurationError("Missing 'app' configuration section")

    # Validate trading config
    if "trading" not in config:
        raise ConfigurationError("Missing 'trading' configuration section")

    trading_config = config["trading"]
    if "session" not in trading_config:
        raise ConfigurationError("Missing 'trading.session' configuration")

    session_config = trading_config["session"]
    validate_time_format(session_config.get("start_time"), "trading.session.start_time")
    validate_time_format(session_config.get("end_time"), "trading.session.end_time")

    # Validate data config
    if "data" in config:
        data_config = config["data"]
        if "timeframes" in data_config:
            validate_timeframes(data_config["timeframes"])

    # Validate model config
    if "models" in config:
        model_config = config["models"]
        if "min_labels_per_pattern" in model_config:
            min_labels = model_config["min_labels_per_pattern"]
            if not isinstance(min_labels, int) or min_labels < 50:
                raise ConfigurationError(
                    "models.min_labels_per_pattern must be an integer >= 50",
                    context={"value": min_labels},
                )


def validate_time_format(time_str: Any, field_name: str) -> None:
    """
    Validate time format (HH:MM).

    Args:
        time_str: Time string to validate
        field_name: Field name for error messages

    Raises:
        ConfigurationError: If time format is invalid
    """
    if not isinstance(time_str, str):
        raise ConfigurationError(
            f"{field_name} must be a string in HH:MM format",
            context={"value": time_str, "field": field_name},
        )

    try:
        parts = time_str.split(":")
        if len(parts) != 2:
            raise ValueError("Invalid format")
        hour = int(parts[0])
        minute = int(parts[1])
        if not (0 <= hour <= 23 and 0 <= minute <= 59):
            raise ValueError("Invalid time range")
    except (ValueError, IndexError) as e:
        raise ConfigurationError(
            f"{field_name} must be in HH:MM format (e.g., '03:00')",
            context={"value": time_str, "field": field_name},
        ) from e


def validate_timeframes(timeframes: List[str]) -> None:
    """
    Validate timeframe list.

    Args:
        timeframes: List of timeframe strings

    Raises:
        ConfigurationError: If timeframes are invalid
    """
    if not isinstance(timeframes, list):
        raise ConfigurationError(
            "data.timeframes must be a list",
            context={"value": timeframes},
        )

    for tf in timeframes:
        if tf not in TIMEFRAMES:
            raise ConfigurationError(
                f"Invalid timeframe: {tf}. Must be one of {TIMEFRAMES}",
                context={"timeframe": tf, "valid_timeframes": TIMEFRAMES},
            )


def validate_file_path(path: str, must_exist: bool = False) -> Path:
    """
    Validate file path.

    Args:
        path: File path string
        must_exist: Whether file must exist

    Returns:
        Path object

    Raises:
        ValidationError: If path is invalid
    """
    try:
        path_obj = Path(path)
        if must_exist and not path_obj.exists():
            raise ValidationError(
                f"Path does not exist: {path}",
                context={"path": str(path)},
            )
        return path_obj
    except Exception as e:
        raise ValidationError(
            f"Invalid path: {path}",
            context={"path": path},
        ) from e


def validate_range(value: float, min_val: float, max_val: float, field_name: str) -> None:
    """
    Validate numeric range.

    Args:
        value: Value to validate
        min_val: Minimum value
        max_val: Maximum value
        field_name: Field name for error messages

    Raises:
        ValidationError: If value is out of range
    """
    if not isinstance(value, (int, float)):
        raise ValidationError(
            f"{field_name} must be a number",
            context={"value": value, "field": field_name},
        )

    if not (min_val <= value <= max_val):
        raise ValidationError(
            f"{field_name} must be between {min_val} and {max_val}",
            context={"value": value, "min": min_val, "max": max_val, "field": field_name},
        )

