"""Config mixin: VM configuration injection, API keys, templates, cloud-init."""

from __future__ import annotations

import json
import secrets
import subprocess
import time
from pathlib import Path
from typing import Any

import structlog

from proxym.virt._config import VMConfig

logger = structlog.get_logger()


class _ConfigMixin:
    """VM configuration injection: API keys, templates, cloud-init rendering."""

    # Registry of VM keys: vm_key → {"vm_id": str, "account_id": str, "created_at": float}
    _vm_key_registry: dict[str, dict[str, Any]] = {}

    def _generate_vm_key(self, vm_id: str, account_id: str = "") -> str:
        """Generuje unikalny klucz API dla VM.

        Klucz nigdy nie opuszcza hosta - VM widzi tylko vm-key, nie prawdziwe klucze API.
        proxym mapuje vm-key-{vm_id} → odpowiednie konto przy zapytaniach.

        Args:
            vm_id: ID maszyny wirtualnej
            account_id: ID konta do którego przypisać VM (opcjonalne)

        Returns:
            Unikalny klucz API dla VM
        """
        key = f"vm-key-{vm_id}-{secrets.token_urlsafe(16)}"
        self._vm_key_registry[key] = {
            "vm_id": vm_id,
            "account_id": account_id,
            "created_at": time.time(),
        }
        logger.info("vm_key_generated", vm_id=vm_id, account_id=account_id)
        return key

    def _get_git_config(self) -> dict[str, str]:
        """Pobiera konfigurację Git z hosta (~/.gitconfig).

        Returns:
            Słownik z user.name i user.email (jeśli skonfigurowane)
        """
        gitconfig_path = Path.home() / ".gitconfig"
        result: dict[str, str] = {}
        if not gitconfig_path.exists():
            return result

        try:
            # Użyj git config do pobrania wartości
            for key in ["user.name", "user.email"]:
                proc = subprocess.run(
                    ["git", "config", "--global", key],
                    capture_output=True,
                    text=True,
                    timeout=5,
                )
                if proc.returncode == 0:
                    result[key] = proc.stdout.strip()
        except Exception as e:
            logger.warning("git_config_read_failed", error=str(e))

        return result

    def _render_template(self, template_content: str, variables: dict[str, str]) -> str:
        """Renderuje template zastępując ${VARIABLE} wartościami.

        Args:
            template_content: Treść template'u z placeholderami ${VAR}
            variables: Słownik zmiennych do podstawienia

        Returns:
            Wyrenderowana treść z zastąpionymi zmiennymi
        """
        result = template_content
        for key, value in variables.items():
            placeholder = f"${{{key}}}"
            result = result.replace(placeholder, value)
        return result

    def _load_profile_cloud_init(self, tool: str) -> dict[str, Any]:
        """Ładuje cloud-init template z profilu YAML.

        Args:
            tool: Nazwa narzędzia/profilu (np. "windsurf-roocode")

        Returns:
            Sekcja cloud_init z profilu lub pusty słownik
        """
        from proxym.virt.profiles import load_profile_yaml, get_builtin_profile

        # Najpierw szukaj w profiles_dir
        profile_path = self.profiles_dir / f"{tool}.clonebox.yaml"
        if not profile_path.exists():
            profile_path = get_builtin_profile(tool)

        if not profile_path:
            return {}

        profile = load_profile_yaml(profile_path)
        return profile.get("cloud_init", {})

    def _inject_vm_config(self, config: VMConfig) -> dict[str, Any]:
        """Generuje cloud-init write_files z wstrzykniętymi wartościami per VM.

        Zastępuje ${VM_API_KEY}, ${PROXY_HOST}, ${PROXY_PORT}, ${GIT_USER_NAME}, etc.

        Args:
            config: Konfiguracja VM

        Returns:
            Wyrenderowana sekcja cloud_init ready do użycia
        """
        # Generuj klucz VM
        vm_key = self._generate_vm_key(config.id, config.account_id)

        # Pobierz konfigurację git
        git_config = self._get_git_config()

        # Domyślny adres proxy (QEMU user network gateway)
        proxy_host = "10.0.2.2"
        proxy_port = "4000"

        # Jeśli VM ma skonfigurowany inny adres proxy
        if config.proxy_address:
            parts = config.proxy_address.rsplit(":", 1)
            if len(parts) == 2:
                proxy_host = parts[0]
                proxy_port = parts[1]

        # Przygotuj zmienne do template'u
        variables = {
            "VM_API_KEY": vm_key,
            "PROXY_HOST": proxy_host,
            "PROXY_PORT": proxy_port,
            "GIT_USER_NAME": git_config.get("user.name", "Developer"),
            "GIT_USER_EMAIL": git_config.get("user.email", "dev@localhost"),
            "VM_ID": config.id,
            "ACCOUNT_ID": config.account_id or "default",
        }

        # Załaduj template cloud-init z profilu
        cloud_init = self._load_profile_cloud_init(config.tool)
        if not cloud_init:
            return {}

        # Wyrenderuj wszystkie write_files
        rendered = json.loads(json.dumps(cloud_init))  # deep copy

        if "write_files" in rendered:
            for item in rendered["write_files"]:
                if "content" in item:
                    item["content"] = self._render_template(item["content"], variables)
                if "path" in item:
                    item["path"] = self._render_template(item["path"], variables)

        # Zapisz mapping klucza VM dla routera
        self._save_vm_key_mapping(vm_key, config)

        logger.info("vm_config_injected", vm_id=config.id, tool=config.tool)
        return rendered

    def _save_vm_key_mapping(self, vm_key: str, config: VMConfig) -> None:
        """Zapisz mapping klucza VM do pliku konfiguracyjnego dla routera.

        Router użyje tego do określenia które konto użyć dla danego klucza.
        """
        key_mapping_path = self.config_dir / "vm_key_mappings.json"
        mappings: dict[str, Any] = {}

        if key_mapping_path.exists():
            try:
                mappings = json.loads(key_mapping_path.read_text())
            except Exception:
                mappings = {}

        mappings[vm_key] = {
            "vm_id": config.id,
            "account_id": config.account_id,
            "tool": config.tool,
            "created_at": time.time(),
        }

        key_mapping_path.write_text(json.dumps(mappings, indent=2, default=str))

    def resolve_vm_key_account(self, vm_key: str) -> str | None:
        """Rozwiąż klucz VM do ID konta.

        Używane przez router do wyboru odpowiedniego konta/API key.

        Args:
            vm_key: Klucz VM (np. "vm-key-windsurf-work-xxx")

        Returns:
            ID konta lub None jeśli klucz nieznany
        """
        # Najpierw sprawdź rejestr w pamięci
        if vm_key in self._vm_key_registry:
            return self._vm_key_registry[vm_key].get("account_id")

        # Potem sprawdź plik
        key_mapping_path = self.config_dir / "vm_key_mappings.json"
        if key_mapping_path.exists():
            try:
                mappings = json.loads(key_mapping_path.read_text())
                if vm_key in mappings:
                    return mappings[vm_key].get("account_id")
            except Exception:
                pass

        return None
