"""AgenticCognition — Longitudinal user modeling for AI agents.

Pure-Python SDK that wraps the ``acog`` CLI binary via subprocess.
Zero required dependencies; only stdlib: subprocess, json, pathlib, dataclasses.
"""

from __future__ import annotations

import json
import logging
import subprocess
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Optional

__version__ = "0.1.0"

logger = logging.getLogger(__name__)


class CognitionError(Exception):
    """Raised when an acog CLI command fails."""


@dataclass
class CognitionStore:
    """Interface to an ``.acog`` cognitive model file.

    Parameters
    ----------
    path : str | Path
        Path to the ``.acog`` file. Created automatically on first write
        if it does not exist.
    binary : str
        Name or path of the ``acog`` CLI binary.
    """

    path: str | Path
    binary: str = "acog"
    _resolved_binary: Optional[str] = field(default=None, repr=False, init=False)

    def __post_init__(self) -> None:
        self.path = Path(self.path)

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _find_binary(self) -> str:
        if self._resolved_binary is not None:
            return self._resolved_binary

        import shutil

        found = shutil.which(self.binary)
        if found is None:
            raise CognitionError(
                f"Cannot find '{self.binary}' on PATH. "
                "Install AgenticCognition: curl -fsSL https://agentralabs.tech/install/cognition | bash"
            )
        self._resolved_binary = found
        return found

    def _run(self, *args: str, check: bool = True) -> str:
        """Execute an acog CLI command and return stdout."""
        cmd = [self._find_binary(), "--file", str(self.path), *args]
        logger.debug("Running: %s", " ".join(cmd))
        result = subprocess.run(cmd, capture_output=True, text=True)
        if check and result.returncode != 0:
            raise CognitionError(
                f"acog command failed (exit {result.returncode}): {result.stderr.strip()}"
            )
        return result.stdout.strip()

    def _run_json(self, *args: str) -> Any:
        """Execute a command and parse JSON output."""
        raw = self._run(*args, "--format", "json")
        return json.loads(raw) if raw else {}

    # ------------------------------------------------------------------
    # Model operations
    # ------------------------------------------------------------------

    def create_model(
        self,
        name: str,
        *,
        domain: Optional[str] = None,
    ) -> str:
        """Create a new cognitive model. Returns the model ID."""
        args = ["model", "create", name]
        if domain:
            args.extend(["--domain", domain])
        return self._run(*args)

    def update_model(
        self,
        name: str,
        *,
        belief: Optional[str] = None,
        confidence: float = 0.7,
    ) -> str:
        """Update a cognitive model with a new belief. Returns confirmation."""
        args = ["model", "update", name]
        if belief:
            args.extend(["--belief", belief])
        args.extend(["--confidence", str(confidence)])
        return self._run(*args)

    def query_model(self, name: str) -> dict[str, Any]:
        """Query a cognitive model. Returns model state as JSON."""
        return self._run_json("model", "query", name)

    def list_models(self) -> list[dict[str, Any]]:
        """List all cognitive models."""
        raw = self._run("model", "list", "--format", "json")
        return json.loads(raw) if raw else []

    # ------------------------------------------------------------------
    # Stats
    # ------------------------------------------------------------------

    def stats(self) -> dict[str, Any]:
        """Get cognition store statistics."""
        raw = self._run("stats", "--format", "json")
        return json.loads(raw) if raw else {}

    # ------------------------------------------------------------------
    # File operations
    # ------------------------------------------------------------------

    def save(self) -> None:
        """Explicit save (most operations auto-save)."""
        pass

    @property
    def exists(self) -> bool:
        """Whether the .acog file exists on disk."""
        return self.path.exists()
