"""Environment-based configuration for qRemoteX agent."""

from __future__ import annotations

import json
import logging
import os
import platform
import socket
import uuid

_config_logger = logging.getLogger("qremotex.config")


class ExecutorConfig:
    """Configuration loaded from environment variables.

    All secrets (API key) are read from env vars only — never hard-coded.
    """

    def __init__(self) -> None:
        # --- Required ---
        self.gateway_url: str = os.environ.get("QRAPTOR_GATEWAY_URL", "")
        self.api_key: str = os.environ.get("QRAPTOR_API_KEY", "")

        # --- Identity (server resolves authoritative ID from API key binding) ---
        self.executor_id: str = os.environ.get("QRAPTOR_EXECUTOR_ID", str(uuid.uuid4()))
        self.executor_name: str = os.environ.get("QRAPTOR_EXECUTOR_NAME", socket.gethostname())

        # --- Execution ---
        self.concurrency: int = int(os.environ.get("CONCURRENCY", "25"))
        self.heartbeat_sec: int = int(os.environ.get("HEARTBEAT_SEC", "20"))
        self.reconnect_max_sec: int = int(os.environ.get("RECONNECT_MAX_SEC", "60"))
        self.exec_timeout_sec: int = int(os.environ.get("EXEC_TIMEOUT_SEC", "300"))
        self.max_script_size_kb: int = int(os.environ.get("MAX_SCRIPT_SIZE_KB", "512"))
        self.max_memory_mb: int = int(os.environ.get("MAX_MEMORY_MB", "2048"))

        # --- Tool control ---
        self.enable_system_tools: bool = os.environ.get("ENABLE_SYSTEM_TOOLS", "true").lower() == "true"
        self.enable_user_tools: bool = os.environ.get("ENABLE_USER_TOOLS", "true").lower() == "true"
        _allowed = os.environ.get("ALLOWED_TOOL_KEYS", "*")
        self.allowed_tool_keys: list[str] | str = _allowed if _allowed == "*" else [k.strip() for k in _allowed.split(",") if k.strip()]
        _blocked = os.environ.get("BLOCKED_TOOL_KEYS", "")
        self.blocked_tool_keys: list[str] = [k.strip() for k in _blocked.split(",") if k.strip()]

        # --- Labels ---
        _labels = os.environ.get("LABELS", "{}")
        try:
            self.labels: dict[str, str] = json.loads(_labels)
        except (json.JSONDecodeError, TypeError):
            self.labels = {}

        # --- Executor group (HA / failover) ---
        self.group: str = os.environ.get("QRAPTOR_EXECUTOR_GROUP", "")

        # --- Logging ---
        self.log_level: str = os.environ.get("LOG_LEVEL", "INFO").upper()

        # --- Derived ---
        self.version: str = "2.0.0"

    # ------------------------------------------------------------------ #
    # Validation
    # ------------------------------------------------------------------ #
    def validate(self) -> list[str]:
        """Return a list of configuration errors (empty = valid)."""
        errors: list[str] = []
        if not self.gateway_url:
            errors.append("QRAPTOR_GATEWAY_URL is required")
        if not self.api_key:
            errors.append("QRAPTOR_API_KEY is required")
        if not self.gateway_url.startswith(("ws://", "wss://")):
            errors.append("QRAPTOR_GATEWAY_URL must start with ws:// or wss://")
        if self.concurrency < 1:
            errors.append("CONCURRENCY must be >= 1")
        if self.heartbeat_sec < 5:
            errors.append("HEARTBEAT_SEC must be >= 5")
        return errors

    # ------------------------------------------------------------------ #
    # Capability & system info builders
    # ------------------------------------------------------------------ #
    def build_capabilities(self) -> list[str]:
        caps = ["python:execute:unrestricted"]
        if self.enable_system_tools:
            caps.append("tools:system")
        if self.enable_user_tools:
            caps.append("tools:user")
        caps.append("file:transfer")
        caps.append(f"concurrency:{self.concurrency}")
        return caps

    def build_system_info(self) -> dict:
        import psutil

        mem = psutil.virtual_memory()
        return {
            "os": platform.system().lower(),
            "arch": platform.machine(),
            "python_version": platform.python_version(),
            "memory_gb": round(mem.total / (1024**3), 1),
            "cpu_cores": os.cpu_count() or 1,
        }

    # ------------------------------------------------------------------ #
    # Parse API key components
    # ------------------------------------------------------------------ #
    def parse_api_key_id(self) -> str:
        """Extract key_id from API key matching server-side generation.

        Server generates: rawKey = Base64Url(32 bytes)
                         prefix = rawKey[:8].lower()
                         fullKey = "qrx_{prefix}_{rawKey}"
                         key_id  = "ak_" + rawKey[:12].lower()

        Key layout (fixed offsets):
            qrx_        → 4 chars (positions 0-3)
            {prefix}    → 8 chars (positions 4-11)
            _           → 1 char  (position 12)
            {rawKey}    → rest    (position 13+)

        IMPORTANT: Cannot use split("_") because Base64 URL encoding
        uses '_' as a valid character, so rawKey and prefix may contain
        underscores. Fixed-offset extraction is the only safe approach.
        """
        if (
            len(self.api_key) >= 25
            and self.api_key[:4] == "qrx_"
            and self.api_key[12] == "_"
        ):
            raw_key = self.api_key[13:]
            return f"ak_{raw_key[:12].lower()}"
        # Fallback: hash-based (won't match server, but allows startup)
        import hashlib
        h = hashlib.sha256(self.api_key.encode()).hexdigest()[:12]
        return f"ak_{h}"

    def api_key_prefix(self) -> str:
        """Return display prefix (first 14 chars + mask)."""
        if len(self.api_key) > 14:
            return self.api_key[:14] + "****"
        return self.api_key
