"""
Base utilities and data classes for the Tradier API client.
"""

from __future__ import annotations

from datetime import date, datetime
from typing import TYPE_CHECKING, Any, TypeVar

from pydantic import BaseModel, ConfigDict

from optrabot.broker.tradier.exceptions import TradierAPIError

if TYPE_CHECKING:
    from httpx import Response


class TradierData(BaseModel):
    """
    Base class for all Tradier data models.
    
    Uses Pydantic's BaseModel with custom configuration for
    flexible field handling and alias support.
    """

    model_config = ConfigDict(
        populate_by_name=True,
        use_enum_values=True,
        extra="ignore",
    )


T = TypeVar("T", bound=TradierData)


def validate_response(response: Response) -> None:
    """
    Validate an HTTP response and raise an exception if it indicates an error.
    
    :param response: The httpx Response object to validate.
    :raises TradierAPIError: If the response indicates an error.
    """
    if response.status_code // 100 != 2:
        try:
            error_data = response.json()
            if "fault" in error_data:
                fault = error_data["fault"]
                message = fault.get("faultstring", "Unknown error")
            elif "errors" in error_data:
                errors = error_data["errors"]
                if isinstance(errors, dict) and "error" in errors:
                    message = errors["error"]
                else:
                    message = str(errors)
            else:
                message = response.text
        except Exception:
            message = response.text or f"HTTP {response.status_code}"
        
        raise TradierAPIError(
            message=message,
            status_code=response.status_code,
        )


def validate_and_parse(response: Response) -> dict[str, Any]:
    """
    Validate an HTTP response and parse JSON data.
    
    :param response: The httpx Response object to validate and parse.
    :returns: The parsed JSON data as a dictionary.
    :raises TradierAPIError: If the response indicates an error.
    """
    validate_response(response)
    return response.json()  # type: ignore[no-any-return]


def parse_datetime(value: str | None) -> datetime | None:
    """
    Parse a datetime string from the Tradier API.
    
    :param value: The datetime string to parse.
    :returns: A datetime object or None if the input is None.
    """
    if value is None:
        return None
    
    # Tradier uses ISO 8601 format
    try:
        return datetime.fromisoformat(value.replace("Z", "+00:00"))
    except ValueError:
        # Try alternative formats
        for fmt in ["%Y-%m-%dT%H:%M:%S.%f%z", "%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%d"]:
            try:
                return datetime.strptime(value, fmt)
            except ValueError:
                continue
        raise ValueError(f"Unable to parse datetime: {value}") from None


def parse_date(value: str | None) -> date | None:
    """
    Parse a date string from the Tradier API.
    
    :param value: The date string to parse.
    :returns: A date object or None if the input is None.
    """
    if value is None:
        return None
    
    return datetime.strptime(value, "%Y-%m-%d").date()
