"""Configuration management for Purrio CLI."""

import os
from enum import Enum
from pathlib import Path

from dotenv import load_dotenv
from pydantic import BaseModel, Field, field_validator
from pydantic_core import ValidationError


class OutputFormat(str, Enum):
    """Supported output formats."""

    TABLE = "table"
    JSON = "json"
    CSV = "csv"


class Network(str, Enum):
    """Supported networks."""

    MAINNET = "mainnet"
    TESTNET = "testnet"


class Config(BaseModel):
    """Application configuration."""

    account_address: str | None = Field(
        default=None,
        description="Wallet address for read operations",
    )
    secret_key: str | None = Field(
        default=None,
        description="Private key for trading operations (keep secure!)",
    )
    api_url: str = Field(
        default="https://api.hyperliquid.xyz",
        description="Hyperliquid API URL",
    )
    output_format: OutputFormat = Field(
        default=OutputFormat.TABLE,
        description="Default output format",
    )
    network: Network = Field(
        default=Network.MAINNET,
        description="Network to connect to",
    )

    @field_validator("account_address")
    @classmethod
    def validate_address(cls, v: str | None) -> str | None:
        """Validate Ethereum address format."""
        if v is None:
            return v
        if not v.startswith("0x"):
            raise ValueError("Address must start with 0x")
        if len(v) != 42:
            raise ValueError("Address must be 42 characters long")
        try:
            int(v[2:], 16)
        except ValueError as e:
            raise ValueError("Invalid hexadecimal address") from e
        return v.lower()

    @field_validator("secret_key")
    @classmethod
    def validate_secret_key(cls, v: str | None) -> str | None:
        """Validate private key format."""
        if v is None:
            return v
        if not v.startswith("0x"):
            raise ValueError("Private key must start with 0x")
        if len(v) != 66:
            raise ValueError("Private key must be 66 characters long")
        try:
            int(v[2:], 16)
        except ValueError as e:
            raise ValueError("Invalid hexadecimal private key") from e
        return v

    @field_validator("api_url")
    @classmethod
    def validate_api_url(cls, v: str) -> str:
        """Validate and normalize API URL."""
        v = v.rstrip("/")
        if not v.startswith(("http://", "https://")):
            raise ValueError("API URL must start with http:// or https://")
        return v

    def update_for_network(self) -> None:
        """Update API URL based on network selection."""
        if self.network == Network.TESTNET:
            self.api_url = "https://api.hyperliquid-testnet.xyz"
        else:
            self.api_url = "https://api.hyperliquid.xyz"

    def mask_secret_key(self) -> str:
        """Return masked version of secret key for display."""
        if not self.secret_key:
            return "Not configured"
        return f"{self.secret_key[:6]}...{self.secret_key[-4:]}"

    class Config:
        """Pydantic config."""

        str_strip_whitespace = True
        use_enum_values = True


def load_config(env_file: Path | None = None) -> Config:
    """
    Load configuration from environment variables.

    Args:
        env_file: Optional path to .env file

    Returns:
        Config: Loaded configuration

    Raises:
        ValidationError: If configuration is invalid
    """
    if env_file and env_file.exists():
        load_dotenv(env_file)
    else:
        load_dotenv()

    try:
        config = Config(
            account_address=os.getenv("PURRIO_ACCOUNT_ADDRESS"),
            secret_key=os.getenv("PURRIO_SECRET_KEY"),
            api_url=os.getenv("PURRIO_API_URL", "https://api.hyperliquid.xyz"),
            output_format=OutputFormat(os.getenv("PURRIO_OUTPUT_FORMAT", OutputFormat.TABLE.value)),
            network=Network(os.getenv("PURRIO_NETWORK", Network.MAINNET.value)),
        )
        config.update_for_network()
        return config
    except ValidationError as e:
        raise ValueError(f"Invalid configuration: {e}") from e


def validate_trading_config(config: Config) -> None:
    """
    Validate that configuration is sufficient for trading operations.

    Args:
        config: Configuration to validate

    Raises:
        ValueError: If configuration is insufficient for trading
    """
    if not config.secret_key:
        raise ValueError(
            "Trading operations require PURRIO_SECRET_KEY to be configured. Set it in your environment or .env file."
        )
    if not config.account_address:
        raise ValueError(
            "Trading operations require PURRIO_ACCOUNT_ADDRESS to be configured. "
            "Set it in your environment or .env file."
        )
