"""Type definitions for the GraphMem Python SDK."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Literal, Optional, Union


# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------


@dataclass
class RetryConfig:
    """Retry configuration for transient failures."""

    max_retries: int = 3
    base_delay: float = 0.5
    max_delay: float = 10.0
    retry_on: list[int] = field(default_factory=lambda: [429, 500, 502, 503, 504])


@dataclass
class RateLimitInfo:
    """Rate limit info parsed from response headers."""

    remaining: Optional[int] = None
    limit: Optional[int] = None
    reset: Optional[int] = None


# ---------------------------------------------------------------------------
# Core: remember
# ---------------------------------------------------------------------------


@dataclass
class ConflictResolution:
    """A single contradiction resolution returned by remember()."""

    subject_name: str
    predicate: str
    old_object: str
    new_object: str
    resolution: str


@dataclass
class RememberResult:
    extracted_count: int
    merged_count: int
    message: str
    conflicts: Optional[list[ConflictResolution]] = None


# ---------------------------------------------------------------------------
# Core: getContext
# ---------------------------------------------------------------------------


@dataclass
class ContextOptions:
    format: Optional[Literal["json", "markdown", "text"]] = None
    mode: Optional[Literal["graph", "hybrid"]] = None


@dataclass
class ContextResultJson:
    format: Literal["json"]
    query: str
    entities: list[dict[str, Any]]
    edges: list[dict[str, Any]]
    trace_id: Optional[str] = None
    vector_entities: Optional[list[dict[str, Any]]] = None
    communities: Optional[list[dict[str, Any]]] = None


@dataclass
class ContextResultText:
    format: Literal["markdown", "text"]
    query: str
    content: str
    trace_id: Optional[str] = None


ContextResult = Union[ContextResultJson, ContextResultText]


# ---------------------------------------------------------------------------
# Core: search
# ---------------------------------------------------------------------------


@dataclass
class SearchResult:
    entity: dict[str, Any]
    edges: list[dict[str, Any]]


# ---------------------------------------------------------------------------
# Graph: triples
# ---------------------------------------------------------------------------


@dataclass
class Triple:
    subject: str
    predicate: str
    object: str


@dataclass
class IngestResult:
    count: int
    message: str


# ---------------------------------------------------------------------------
# Graph: full graph
# ---------------------------------------------------------------------------


@dataclass
class GraphNode:
    id: str
    name: str
    created_at: Optional[int] = None
    source_type: Optional[str] = None
    source_uri: Optional[str] = None


@dataclass
class GraphEdge:
    id: str
    source: str
    target: str
    type: str
    updated_at: int = 0
    created_at: Optional[int] = None
    weight: float = 1.0


@dataclass
class GraphCommunity:
    id: str
    community_id: int
    name: str
    member_node_ids: list[str] = field(default_factory=list)
    color: str = ""


@dataclass
class GraphData:
    nodes: list[GraphNode]
    edges: list[GraphEdge]
    communities: Optional[list[GraphCommunity]] = None


# ---------------------------------------------------------------------------
# Graph: import / export
# ---------------------------------------------------------------------------


@dataclass
class ExportData:
    version: int
    triples: list[dict[str, Any]]


@dataclass
class ImportResult:
    imported: int
    message: str


# ---------------------------------------------------------------------------
# Communities
# ---------------------------------------------------------------------------


@dataclass
class Community:
    id: str
    community_id: int
    name: str
    summary: str
    member_count: int
    created_at: Optional[int] = None
    updated_at: Optional[int] = None


@dataclass
class DetectCommunitiesResult:
    community_count: int
    entity_count: int
    message: str


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


@dataclass
class Trace:
    id: str
    query: str
    format: str
    mode: str
    entity_count: int
    edge_count: int
    created_at: int = 0


@dataclass
class TraceDetail(Trace):
    entities: list[dict[str, Any]] = field(default_factory=list)
    edges: list[dict[str, Any]] = field(default_factory=list)


# ---------------------------------------------------------------------------
# Blacklist
# ---------------------------------------------------------------------------


@dataclass
class BlacklistedTriple:
    id: str
    subject: str
    predicate: str
    object: str
    created_at: int = 0


# ---------------------------------------------------------------------------
# Conflict log
# ---------------------------------------------------------------------------


@dataclass
class ConflictLogEntry:
    """An entry in the conflict resolution log."""

    id: str
    subject_name: str
    predicate: str
    old_object: str
    new_object: str
    resolution: str
    created_at: str


# ---------------------------------------------------------------------------
# Pending facts
# ---------------------------------------------------------------------------


@dataclass
class PendingFact:
    id: str
    subject: str
    predicate: str
    object: str
    status: str
    created_at: int = 0


# ---------------------------------------------------------------------------
# Projects
# ---------------------------------------------------------------------------


@dataclass
class Project:
    id: str
    name: str
    created_at: int = 0


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


@dataclass
class UsageInfo:
    tier: str
    fact_limit: int
    current_facts: int
    nodes_count: int
    edges_count: int
    file_storage_limit: int = 0
    file_count_limit: int = 0
    current_file_storage: int = 0
    current_file_count: int = 0


# ---------------------------------------------------------------------------
# Health
# ---------------------------------------------------------------------------


@dataclass
class HealthResult:
    status: str
    version: str
    timestamp: str


# ---------------------------------------------------------------------------
# FilesRag
# ---------------------------------------------------------------------------


@dataclass
class MemoryFile:
    id: str
    name: str
    path: str
    size: int
    created_at: str
    updated_at: str
    chunk_count: Optional[int] = None


@dataclass
class FileWithContent:
    id: str
    name: str
    path: str
    size: int
    content: str
    created_at: str
    updated_at: str
    chunk_count: Optional[int] = None


@dataclass
class FileChunkResult:
    heading_title: str
    excerpt: str
    score: float


@dataclass
class FileSearchResult:
    file: dict[str, Any]
    chunks: list[FileChunkResult]


@dataclass
class WriteFileResult:
    file: MemoryFile
    chunk_count: int
    created: bool
