"""GoldHold Python SDK -- thin client for relay.goldhold.ai.
Patent Pending. All Auto Tunes LLC. U.S. #63/988,484.
"""

import json
import os
from pathlib import Path

import requests

from .exceptions import AuthError, GoldHoldError, RateLimitError, VectorLimitError
from .types import (
    AutoResponse, BatchResponse, CloseResponse, Memory,
    SessionContext, StatusResponse, StoreResult, TurnResponse,
)

__version__ = "0.1.0"
_UA = "goldhold-python/{}".format(__version__)
_CONFIG_PATH = Path.home() / ".goldhold" / "config.json"


class GoldHold:
    """Thin client for the GoldHold relay API."""

    def __init__(self, api_key=None, base_url="https://relay.goldhold.ai"):
        if api_key is None:
            api_key = os.environ.get("GOLDHOLD_API_KEY") or self._load_config_key()
        if not api_key:
            raise AuthError("No API key. Set GOLDHOLD_API_KEY, pass api_key=, or run GoldHold.setup().")
        self._key = api_key
        self._base = base_url.rstrip("/")
        self._session = requests.Session()
        self._session.headers.update({
            "Authorization": "Bearer {}".format(api_key),
            "User-Agent": _UA,
            "Content-Type": "application/json",
        })

    # -- public API --

    def turn(self, search=None, store=None, send=None, compact=True):
        body = {"compact": compact}
        if search is not None:
            body["search"] = search
        if store is not None:
            body["store"] = store
        if send is not None:
            body["send"] = send
        return TurnResponse.from_dict(self._post("/v1/turn", body))

    def auto(self, context_budget=2000):
        return AutoResponse.from_dict(self._post("/v1/auto", {"context_budget": context_budget}))

    def batch(self, operations):
        return BatchResponse.from_dict(self._post("/v1/batch", {"operations": operations}))

    def close(self, session_summary=None):
        body = {}
        if session_summary:
            body["session_summary"] = session_summary
        return CloseResponse.from_dict(self._post("/v1/session/close", body))

    def search(self, query, limit=5, filters=None):
        body = {"search": {"query": query, "limit": limit}, "compact": True}
        if filters:
            body["search"]["filters"] = filters
        data = self._post("/v1/turn", body)
        return [Memory.from_dict(m) for m in data.get("search_results", data.get("results", []))]

    def store(self, subject, body, type="NOTE", confidence="medium"):
        payload = {"store": [{"subject": subject, "body": body, "type": type, "confidence": confidence}], "compact": True}
        data = self._post("/v1/turn", payload)
        stored = data.get("stored", [])
        if isinstance(stored, list) and stored:
            return StoreResult.from_dict(stored[0])
        elif isinstance(stored, dict):
            return StoreResult.from_dict(stored)
        return StoreResult()

    def status(self):
        return StatusResponse.from_dict(self._get("/v1/status"))

    @staticmethod
    def setup():
        """Interactive CLI setup -- prints signup URL, prompts for key, saves config."""
        print("GoldHold Setup")
        print("-" * 40)
        print("1. Sign up or log in at: https://goldhold.ai/account")
        print("2. Copy your API key from the dashboard.\n")
        api_key = input("Paste your API key: ").strip()
        if not api_key:
            print("No key entered. Aborting.")
            return
        _CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
        config = {}
        if _CONFIG_PATH.exists():
            try:
                config = json.loads(_CONFIG_PATH.read_text())
            except Exception:
                pass
        config["api_key"] = api_key
        _CONFIG_PATH.write_text(json.dumps(config, indent=2))
        print("Saved to {}".format(_CONFIG_PATH))
        # Quick verify
        try:
            gh = GoldHold(api_key=api_key)
            s = gh.status()
            print("Connected! Namespace: {} | Vectors: {}".format(s.namespace, s.total_vectors))
        except Exception as e:
            print("Warning: could not verify key -- {}".format(e))

    # -- internals --

    def _post(self, path, body):
        r = self._session.post(self._base + path, json=body)
        return self._handle(r)

    def _get(self, path):
        r = self._session.get(self._base + path)
        return self._handle(r)

    @staticmethod
    def _handle(r):
        if r.status_code == 401:
            raise AuthError("Invalid or expired API key.", 401, r)
        if r.status_code == 429:
            try:
                data = r.json()
            except Exception:
                data = {}
            if data.get("code") == "VECTOR_LIMIT_REACHED" or "vector" in data.get("error", "").lower():
                raise VectorLimitError(data.get("error", "Vector limit reached"), r)
            raise RateLimitError(data.get("error", "Rate limited"), 429, r)
        if r.status_code >= 500:
            raise GoldHoldError("Server error: {}".format(r.status_code), r.status_code, r)
        if r.status_code >= 400:
            try:
                msg = r.json().get("error", r.text)
            except Exception:
                msg = r.text
            raise GoldHoldError(msg, r.status_code, r)
        try:
            return r.json()
        except Exception:
            return {}

    @staticmethod
    def _load_config_key():
        if _CONFIG_PATH.exists():
            try:
                return json.loads(_CONFIG_PATH.read_text()).get("api_key")
            except Exception:
                return None
        return None
