"""Configuration management for the Bamboo Claw client agent."""

import sys
import uuid
from dataclasses import dataclass, field
from pathlib import Path
from urllib.parse import urlsplit, urlunsplit

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib

import tomli_w


DEFAULT_CONFIG_DIR = Path.home() / ".bamboo_claw"
DEFAULT_CONFIG_PATH = DEFAULT_CONFIG_DIR / "bamboo_claw.toml"
LEGACY_CONFIG_PATH = DEFAULT_CONFIG_DIR / "config.toml"
DEFAULT_GATEWAY_URL = "ws://127.0.0.1:18789"
CLIENT_WS_PATH = "/ws/client"


def _generate_client_id() -> str:
    """Generate a stable unique client identifier (UUID4)."""
    return str(uuid.uuid4())


def build_server_ws_url(server_url: str) -> str:
    """Build the client WebSocket URL from an HTTP(S) or WS(S) server URL."""
    normalized = server_url.strip()
    if not normalized:
        return CLIENT_WS_PATH

    parsed = urlsplit(normalized)
    scheme = parsed.scheme
    if scheme == "http":
        scheme = "ws"
    elif scheme == "https":
        scheme = "wss"

    path = (parsed.path or "").rstrip("/")
    if not path.endswith(CLIENT_WS_PATH):
        path = f"{path}{CLIENT_WS_PATH}" if path else CLIENT_WS_PATH

    if parsed.scheme:
        return urlunsplit((scheme, parsed.netloc, path, parsed.query, parsed.fragment))

    # Fall back to the previous behavior for unknown/bare inputs.
    return normalized.rstrip("/") + CLIENT_WS_PATH


@dataclass
class ClientConfig:
    server_url: str = ""
    token: str = ""
    client_id: str = ""
    gateway_url: str = DEFAULT_GATEWAY_URL
    gateway_token: str = ""
    hostname: str = ""

    def ensure_client_id(self) -> str:
        """Ensure a client_id exists, generating one if needed."""
        if not self.client_id:
            self.client_id = _generate_client_id()
        return self.client_id

    @property
    def ws_url(self) -> str:
        """Full WebSocket URL with /ws/client path appended if missing."""
        return build_server_ws_url(self.server_url)

    @classmethod
    def load(cls, path: Path | None = None) -> "ClientConfig":
        config_path = resolve_config_path(path)
        if not config_path.exists():
            return cls()

        with open(config_path, "rb") as f:
            data = tomllib.load(f)

        return cls(
            server_url=data.get("server", {}).get("url", ""),
            token=data.get("auth", {}).get("token", ""),
            client_id=data.get("auth", {}).get("client_id", ""),
            gateway_url=data.get("gateway", {}).get("url", DEFAULT_GATEWAY_URL),
            gateway_token=data.get("gateway", {}).get("token", ""),
            hostname=data.get("client", {}).get("hostname", ""),
        )

    def save(self, path: Path | None = None) -> None:
        config_path = path or DEFAULT_CONFIG_PATH
        config_path.parent.mkdir(parents=True, exist_ok=True)

        data = {}

        if self.server_url:
            data["server"] = {"url": self.server_url}

        if self.token or self.client_id:
            auth = {}
            if self.token:
                auth["token"] = self.token
            if self.client_id:
                auth["client_id"] = self.client_id
            data["auth"] = auth

        if self.hostname:
            data["client"] = {"hostname": self.hostname}

        gateway = {"url": self.gateway_url}
        if self.gateway_token:
            gateway["token"] = self.gateway_token
        data["gateway"] = gateway

        with open(config_path, "wb") as f:
            tomli_w.dump(data, f)


def resolve_config_path(path: Path | None = None) -> Path:
    """Resolve the effective config path, including legacy fallback behavior."""
    if path is not None:
        return path
    if DEFAULT_CONFIG_PATH.exists():
        return DEFAULT_CONFIG_PATH
    if LEGACY_CONFIG_PATH.exists():
        return LEGACY_CONFIG_PATH
    return DEFAULT_CONFIG_PATH
