from __future__ import annotations

import json
import os
import sys
import tempfile

from aegro.config import Settings
from aegro.errors import FarmNotFoundError, NoFarmSelectedError
from aegro.cli._auth import load_credentials
from aegro.cli._client import SyncAegroClient
from aegro.cli._paths import get_config_dir, _atomic_replace

AEGRO_ACTIVE_FARM_ENV = "AEGRO_ACTIVE_FARM"

_settings: Settings | None = None
_client: SyncAegroClient | None = None


def get_settings() -> Settings:
    """Build Settings merging credentials from _auth.py.

    Priority: env vars (AEGRO_FARMS, AEGRO_FARMS_FILE) > credentials.json.
    The _auth.load_credentials() handles this priority order internally.
    """
    global _settings
    if _settings is None:
        farms = load_credentials()
        _settings = Settings(farms=farms) if farms else Settings()
    return _settings


def get_client() -> SyncAegroClient:
    global _client
    if _client is None:
        s = get_settings()
        _client = SyncAegroClient(
            base_url=s.aegro_api_base_url,
            timeout=s.api_timeout,
            max_retries=s.api_max_retries,
        )
    return _client


def _env_active_farm() -> str | None:
    """Read AEGRO_ACTIVE_FARM. Empty/whitespace-only is treated as unset."""
    value = os.environ.get(AEGRO_ACTIVE_FARM_ENV)
    if value is None:
        return None
    value = value.strip()
    return value or None


def _state_file_farm() -> str | None:
    state_file = get_config_dir() / "state.json"
    if not state_file.exists():
        return None
    try:
        data = json.loads(state_file.read_text(encoding="utf-8"))
        return data.get("selected_farm")
    except (json.JSONDecodeError, UnicodeDecodeError):
        print(
            f"aegro: aviso: state.json corrompido ({state_file}). "
            "Execute 'aegro farms select <nome>' novamente.",
            file=sys.stderr,
        )
        return None
    except OSError as exc:
        print(f"aegro: aviso: nao foi possivel ler {state_file}: {exc}", file=sys.stderr)
        return None


def get_active_farm_source() -> str:
    """Where the active farm comes from: 'env', 'state', or 'none'."""
    if _env_active_farm() is not None:
        return "env"
    if _state_file_farm() is not None:
        return "state"
    return "none"


def get_selected_farm() -> str | None:
    """Return the active farm name.

    Priority: AEGRO_ACTIVE_FARM env var > state.json.
    The env var lets Claude Cowork (and other orchestrators) scope the
    active farm to a single session without racing the global state file.
    """
    env_value = _env_active_farm()
    if env_value is not None:
        return env_value
    return _state_file_farm()


def set_selected_farm(farm_name: str) -> None:
    config_dir = get_config_dir()
    config_dir.mkdir(parents=True, exist_ok=True)
    state_file = config_dir / "state.json"
    data: dict = {}
    if state_file.exists():
        try:
            data = json.loads(state_file.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, UnicodeDecodeError, OSError) as exc:
            print(
                f"aegro: aviso: state.json corrompido ({state_file}): {exc}. "
                "O estado sera recriado.",
                file=sys.stderr,
            )
            data = {}

    data["selected_farm"] = farm_name
    content = json.dumps(data, indent=2, ensure_ascii=False)

    # Atomic write
    fd, tmp_path = tempfile.mkstemp(dir=str(config_dir), suffix=".tmp")
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as f:
            f.write(content)
        _atomic_replace(tmp_path, str(state_file))
    except BaseException:
        try:
            os.unlink(tmp_path)
        except OSError:
            pass
        raise


def require_farm(settings: Settings | None = None) -> tuple[str, str]:
    """Get selected farm name and API key, or raise."""
    if settings is None:
        settings = get_settings()
    farm_name = get_selected_farm()
    if farm_name is None:
        raise NoFarmSelectedError(available_farms=settings.farm_names())
    api_key = settings.get_api_key(farm_name)
    if api_key is None:
        raise FarmNotFoundError(farm_name)
    return farm_name, api_key
