"""
Cloud backend for Novyx MCP.

Thin wrapper around the Novyx Python SDK client.
Preserves exact existing behavior — every method delegates to the SDK.
"""

from __future__ import annotations

import os
from typing import Any

from novyx import Novyx


class CloudBackend:
    """Delegates all operations to the Novyx Cloud API via the Python SDK."""

    def __init__(self) -> None:
        api_key = os.environ.get("NOVYX_API_KEY")
        if not api_key:
            raise ValueError("NOVYX_API_KEY environment variable is required")
        try:
            self._client = Novyx(api_key=api_key, source="mcp")
        except TypeError:
            # Older SDK versions don't accept source=
            self._client = Novyx(api_key=api_key)

    # ------------------------------------------------------------------
    # Core Memory
    # ------------------------------------------------------------------

    def remember(self, observation: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.remember(observation, **kwargs)

    def recall(self, query: str, **kwargs: Any) -> Any:
        """Returns the SDK's SearchResult object."""
        return self._client.recall(query, **kwargs)

    def forget(self, memory_id: str) -> bool:
        return self._client.forget(memory_id)

    def memories(self, **kwargs: Any) -> list[dict[str, Any]]:
        return self._client.memories(**kwargs)

    def memory(self, memory_id: str) -> dict[str, Any]:
        return self._client.memory(memory_id)

    def stats(self) -> dict[str, Any]:
        return self._client.stats()

    def draft_memory(self, observation: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.draft_memory(observation, **kwargs)

    def memory_drafts(self, **kwargs: Any) -> dict[str, Any]:
        return self._client.memory_drafts(**kwargs)

    def memory_draft(self, draft_id: str) -> dict[str, Any]:
        return self._client.memory_draft(draft_id)

    def draft_diff(self, draft_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.draft_diff(draft_id, **kwargs)

    def merge_draft(self, draft_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.merge_draft(draft_id, **kwargs)

    def reject_draft(self, draft_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.reject_draft(draft_id, **kwargs)

    def memory_branch(self, branch_id: str) -> dict[str, Any]:
        return self._client.memory_branch(branch_id)

    def merge_branch(self, branch_id: str) -> dict[str, Any]:
        return self._client.merge_branch(branch_id)

    def reject_branch(self, branch_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.reject_branch(branch_id, **kwargs)

    # ------------------------------------------------------------------
    # Rollback & Audit
    # ------------------------------------------------------------------

    def rollback(self, target: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.rollback(target, **kwargs)

    def audit(self, **kwargs: Any) -> list[dict[str, Any]]:
        return self._client.audit(**kwargs)

    # ------------------------------------------------------------------
    # Links & Knowledge Graph
    # ------------------------------------------------------------------

    def link(self, source_id: str, target_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.link(source_id, target_id, **kwargs)

    def triple(self, subject: str, predicate: str, object_name: str) -> dict[str, Any]:
        return self._client.triple(subject, predicate, object_name)

    def triples(self, **kwargs: Any) -> dict[str, Any]:
        return self._client.triples(**kwargs)

    # ------------------------------------------------------------------
    # Context Spaces
    # ------------------------------------------------------------------

    def create_space(self, name: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.create_space(name=name, **kwargs)

    def list_spaces(self) -> dict[str, Any]:
        return self._client.list_spaces()

    def get_space(self, space_id: str) -> dict[str, Any]:
        return self._client.get_space(space_id)

    def update_space(self, space_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.update_space(space_id, **kwargs)

    def delete_space(self, space_id: str) -> None:
        self._client.delete_space(space_id)

    def space_memories(self, space_id: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.space_memories(space_id, **kwargs)

    def share_context(self, tag: str, to_email: str, permission: str = "read") -> dict[str, Any]:
        return self._client.share_context(tag, to_email=to_email, permission=permission)

    # ------------------------------------------------------------------
    # Usage
    # ------------------------------------------------------------------

    def usage(self) -> dict[str, Any]:
        return self._client.usage()

    # ------------------------------------------------------------------
    # Replay (Pro+)
    # ------------------------------------------------------------------

    def replay_timeline(self, **kwargs: Any) -> dict[str, Any]:
        return self._client.replay_timeline(**kwargs)

    def replay_snapshot(self, at: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.replay_snapshot(at, **kwargs)

    def replay_lifecycle(self, memory_id: str) -> dict[str, Any]:
        return self._client.replay_lifecycle(memory_id)

    def replay_diff(self, start: str, end: str) -> dict[str, Any]:
        return self._client.replay_diff(start, end)

    # ------------------------------------------------------------------
    # Cortex (Pro+)
    # ------------------------------------------------------------------

    def cortex_status(self) -> dict[str, Any]:
        return self._client.cortex_status()

    def cortex_run(self) -> dict[str, Any]:
        return self._client.cortex_run()

    def cortex_insights(self, **kwargs: Any) -> dict[str, Any]:
        return self._client.cortex_insights(**kwargs)

    def cortex_config(self) -> dict[str, Any]:
        return self._client.cortex_config()

    def cortex_update_config(self, **kwargs: Any) -> dict[str, Any]:
        return self._client.cortex_update_config(**kwargs)

    # ------------------------------------------------------------------
    # Supersede
    # ------------------------------------------------------------------

    def supersede(self, old_memory_id: str, new_memory_id: str) -> dict[str, Any]:
        return self._client.supersede(old_memory_id, new_memory_id)

    # ------------------------------------------------------------------
    # Links (extended)
    # ------------------------------------------------------------------

    def unlink(self, source_id: str, target_id: str) -> dict[str, Any]:
        return self._client.unlink(source_id, target_id)

    def links(self, memory_id: str, *, relation: str | None = None) -> dict[str, Any]:
        return self._client.links(memory_id, relation=relation)

    def edges(self, *, memory_id: str | None = None, relation: str | None = None,
              direction: str = "both", limit: int = 100) -> dict[str, Any]:
        return self._client.edges(memory_id=memory_id, relation=relation,
                                  direction=direction, limit=limit)

    # ------------------------------------------------------------------
    # Knowledge Graph (extended)
    # ------------------------------------------------------------------

    def delete_triple(self, triple_id: str) -> dict[str, Any]:
        return self._client.delete_triple(triple_id)

    def entities(self, *, limit: int = 100, offset: int = 0,
                 entity_type: str | None = None) -> dict[str, Any]:
        return self._client.entities(limit=limit, offset=offset, entity_type=entity_type)

    def entity(self, entity_id: str) -> dict[str, Any]:
        return self._client.entity(entity_id)

    def delete_entity(self, entity_id: str) -> dict[str, Any]:
        return self._client.delete_entity(entity_id)

    # ------------------------------------------------------------------
    # Rollback (extended)
    # ------------------------------------------------------------------

    def rollback_preview(self, target: str) -> dict[str, Any]:
        return self._client.rollback_preview(target)

    def rollback_history(self, limit: int = 50) -> list[dict[str, Any]]:
        return self._client.rollback_history(limit=limit)

    # ------------------------------------------------------------------
    # Audit (extended)
    # ------------------------------------------------------------------

    def audit_verify(self) -> dict[str, Any]:
        return self._client.audit_verify()

    # ------------------------------------------------------------------
    # Traces
    # ------------------------------------------------------------------

    def trace_create(self, name: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.trace_create(name, **kwargs)

    def trace_step(self, trace_id: str, step_name: str, **kwargs: Any) -> dict[str, Any]:
        return self._client.trace_step(trace_id, step_name, **kwargs)

    def trace_complete(self, trace_id: str) -> dict[str, Any]:
        return self._client.trace_complete(trace_id)

    def trace_verify(self, trace_id: str) -> dict[str, Any]:
        return self._client.trace_verify(trace_id)

    # ------------------------------------------------------------------
    # Eval
    # ------------------------------------------------------------------

    def eval_run(self, *, min_score: float | None = None) -> dict[str, Any]:
        return self._client.eval_run(min_score=min_score)

    def eval_gate(self, min_score: float) -> dict[str, Any]:
        return self._client.eval_gate(min_score)

    def eval_history(self, *, limit: int = 50, offset: int = 0) -> dict[str, Any]:
        return self._client.eval_history(limit=limit, offset=offset)

    def eval_drift(self, *, days: int = 7) -> dict[str, Any]:
        return self._client.eval_drift(days=days)

    # ------------------------------------------------------------------
    # Replay (extended)
    # ------------------------------------------------------------------

    def replay_memory(self, memory_id: str) -> dict[str, Any]:
        return self._client.replay_memory(memory_id)

    def replay_recall(self, query: str, at: str, *, limit: int = 5) -> dict[str, Any]:
        return self._client.replay_recall(query, at, limit=limit)

    def replay_drift(self, from_ts: str, to_ts: str) -> dict[str, Any]:
        return self._client.replay_drift(from_ts, to_ts)

    # ------------------------------------------------------------------
    # Context
    # ------------------------------------------------------------------

    def context_now(self) -> dict[str, Any]:
        return self._client.context_now()

    def dashboard(self) -> dict[str, Any]:
        return self._client.dashboard()

    # ------------------------------------------------------------------
    # Sharing (extended)
    # ------------------------------------------------------------------

    def accept_shared_context(self, token: str) -> dict[str, Any]:
        return self._client.accept_shared_context(token)

    def shared_contexts(self) -> dict[str, Any]:
        return self._client.shared_contexts()

    def revoke_shared_context(self, token: str) -> dict[str, Any]:
        return self._client.revoke_shared_context(token)
