"""
StemeDB HTTP client with Ed25519 signing.

Mirrors the Go SDK pattern from sdk/go/steme/client.go
"""

from dataclasses import dataclass
from typing import Optional

import blake3
import requests

# Support both package and script imports
try:
    from .config import STEMEDB_URL, SOURCE_CLASS_SOCIAL, DEFAULT_LIFECYCLE
    from .signer import Signer
except ImportError:
    from config import STEMEDB_URL, SOURCE_CLASS_SOCIAL, DEFAULT_LIFECYCLE
    from signer import Signer


@dataclass
class AssertionResult:
    """Result from creating an assertion."""

    hash: str
    status: str


@dataclass
class HealthResult:
    """Result from health check."""

    status: str
    version: str
    assertions_count: int


class StemeDBClient:
    """
    StemeDB HTTP API client with automatic signing.

    All assertions are automatically signed using the provided Signer.
    """

    def __init__(self, base_url: str = STEMEDB_URL, signer: Optional[Signer] = None):
        """
        Create a new StemeDB API client.

        Args:
            base_url: API endpoint (e.g., "http://localhost:18180")
            signer: Signer for automatic assertion signing
        """
        self.base_url = base_url.rstrip("/")
        self.signer = signer
        self._session = requests.Session()
        self._session.headers.update(
            {
                "Content-Type": "application/json",
                "Accept": "application/json",
            }
        )
        if signer:
            self._session.headers["X-Agent-Id"] = signer.public_key

    def health(self) -> HealthResult:
        """Check the API health status."""
        resp = self._session.get(f"{self.base_url}/v1/health")
        resp.raise_for_status()
        data = resp.json()
        return HealthResult(
            status=data["status"],
            version=data["version"],
            assertions_count=data["assertions_count"],
        )

    def assert_fact(
        self,
        subject: str,
        predicate: str,
        object_value: str,
        confidence: float,
        source_url: str,
        source_class: str = SOURCE_CLASS_SOCIAL,
        lifecycle: str = DEFAULT_LIFECYCLE,
        source_metadata: Optional[str] = None,
    ) -> AssertionResult:
        """
        Create a new assertion in the knowledge graph.

        The assertion is automatically signed using the client's signer.

        Args:
            subject: Subject entity (e.g., "semaglutide")
            predicate: Predicate/relation (e.g., "side_effect")
            object_value: Object value (e.g., "nausea")
            confidence: Confidence score (0.0 to 1.0)
            source_url: URL of source evidence
            source_class: Source authority tier (default: "Anecdotal")
            lifecycle: Lifecycle stage (default: "Proposed")
            source_metadata: Optional JSON string with structured metadata

        Returns:
            AssertionResult with content-addressed hash

        Raises:
            ValueError: If signer is not configured
            requests.HTTPError: If the API request fails
        """
        if not self.signer:
            raise ValueError("Signer required for assertions")

        # Compute source hash from URL (BLAKE3)
        source_hash = blake3.blake3(source_url.encode("utf-8")).hexdigest()

        # Create signature (v1 format: signs subject:predicate)
        signature = self.signer.create_signature(subject, predicate)

        # Build request payload
        # Note: ObjectValueDto uses adjacently tagged serde format
        payload = {
            "subject": subject,
            "predicate": predicate,
            "object": {"type": "Text", "value": object_value},
            "confidence": confidence,
            "source_hash": source_hash,
            "source_class": source_class,
            "lifecycle": lifecycle,
            "signatures": [
                {
                    "agent_id": signature.agent_id,
                    "signature": signature.signature,
                    "timestamp": signature.timestamp,
                    "version": signature.version,
                }
            ],
        }

        if source_metadata:
            payload["source_metadata"] = source_metadata

        resp = self._session.post(f"{self.base_url}/v1/assert", json=payload)
        resp.raise_for_status()
        data = resp.json()

        return AssertionResult(hash=data["hash"], status=data["status"])

    def store_source(self, content: bytes, content_type: str) -> str:
        """
        Store a source document and return its BLAKE3 hash.

        Args:
            content: Raw content bytes
            content_type: MIME type (e.g., "text/plain")

        Returns:
            Hex-encoded BLAKE3 hash (64 chars)
        """
        import base64

        payload = {
            "content": base64.b64encode(content).decode("ascii"),
            "content_type": content_type,
        }

        resp = self._session.post(f"{self.base_url}/v1/source", json=payload)
        resp.raise_for_status()
        return resp.json()["hash"]
