"""
Hardin Memory — official Python client (zero dependencies)
==========================================================

Drop this single file into your project and you have hardened, poison-proof,
verifiable memory for your AI agent in a few lines. Standard library only.

    from hardin_memory import HardinMemory

    mem = HardinMemory("YOUR_API_KEY")
    mem.remember("Customer prefers email over phone.", kind="fact", source="crm")

    hits = mem.recall("how does the customer like to be contacted?")
    for h in hits["results"]:
        print(h["score"], h["text"], "verified:", h["verified"])

    proof = mem.audit()          # {"verdict": "INTACT", ...}

Every call is hardened and verified automatically — lies can't get in, and you
can prove the memory is clean. Get a key at https://memory.hardinai.co.uk

© 2026 Hardin Enterprises Ltd. Provided for use with the Hardin Memory service.
"""

import json
import urllib.request
import urllib.error

DEFAULT_BASE = "https://memory.hardinai.co.uk"


class HardinMemoryError(Exception):
    """Raised when the API returns an error or is unreachable."""


class HardinMemory:
    def __init__(self, api_key: str, base_url: str = DEFAULT_BASE, timeout: int = 30):
        if not api_key:
            raise ValueError("api_key is required")
        self.api_key = api_key
        self.base = base_url.rstrip("/")
        self.timeout = timeout

    def _call(self, method: str, path: str, body: dict = None) -> dict:
        url = self.base + path
        data = json.dumps(body).encode() if body is not None else None
        req = urllib.request.Request(url, data=data, method=method)
        req.add_header("Authorization", "Bearer " + self.api_key)
        req.add_header("Content-Type", "application/json")
        try:
            with urllib.request.urlopen(req, timeout=self.timeout) as r:
                return json.loads(r.read().decode())
        except urllib.error.HTTPError as e:
            detail = e.read().decode(errors="replace")
            raise HardinMemoryError(f"HTTP {e.code}: {detail}") from None
        except urllib.error.URLError as e:
            raise HardinMemoryError(f"connection error: {e.reason}") from None

    def remember(self, text: str, kind: str = "fact", source: str = "api") -> dict:
        """Store a memory. Returns {shard_id, signed, chain_index, created}."""
        return self._call("POST", "/v1/memory/remember",
                          {"text": text, "kind": kind, "source": source})

    def recall(self, query: str, k: int = 5) -> dict:
        """Find the most relevant VERIFIED memories. Poisoned/forged ones are
        never returned. Returns {query, results:[{text, score, verified, ...}]}."""
        return self._call("POST", "/v1/memory/recall", {"query": query, "k": k})

    def verify(self, shard_id: str) -> dict:
        """Check one memory's seal. Returns {found, valid, ...}."""
        return self._call("GET", "/v1/memory/verify/" + shard_id)

    def audit(self) -> dict:
        """Prove the whole memory is clean. Returns {verdict, ...}."""
        return self._call("GET", "/v1/memory/audit")

    def usage(self) -> dict:
        """Your current usage and plan."""
        return self._call("GET", "/v1/memory/usage")


if __name__ == "__main__":
    import os, sys
    key = os.environ.get("HARDIN_MEMORY_KEY") or (sys.argv[1] if len(sys.argv) > 1 else "")
    if not key:
        print("usage: HARDIN_MEMORY_KEY=... python hardin_memory.py")
        raise SystemExit(1)
    m = HardinMemory(key)
    print("remember:", m.remember("Hello from the Hardin Memory client."))
    print("recall:", m.recall("hello"))
    print("audit:", m.audit())
