"""
Synor Database SDK Types
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Dict, List, Optional, Union
from datetime import datetime


class Network(str, Enum):
    """Network environment."""
    MAINNET = "mainnet"
    TESTNET = "testnet"
    DEVNET = "devnet"


class DistanceMetric(str, Enum):
    """Vector distance metric."""
    COSINE = "cosine"
    EUCLIDEAN = "euclidean"
    DOT_PRODUCT = "dotProduct"


class Aggregation(str, Enum):
    """Time series aggregation function."""
    MEAN = "mean"
    SUM = "sum"
    COUNT = "count"
    MIN = "min"
    MAX = "max"
    FIRST = "first"
    LAST = "last"
    STDDEV = "stddev"
    VARIANCE = "variance"


class SortOrder(str, Enum):
    """Sort order."""
    ASC = "asc"
    DESC = "desc"


@dataclass
class DatabaseConfig:
    """Database configuration."""
    api_key: str
    endpoint: str = "https://database.synor.io/v1"
    network: Network = Network.MAINNET
    timeout: float = 30.0
    retries: int = 3
    debug: bool = False


# ==================== Key-Value Types ====================

@dataclass
class KeyValueEntry:
    """Key-value entry with metadata."""
    key: str
    value: Any
    created_at: int
    updated_at: int
    metadata: Optional[Dict[str, str]] = None
    expires_at: Optional[int] = None


@dataclass
class SetOptions:
    """Options for setting a key-value pair."""
    ttl: Optional[int] = None  # Time-to-live in seconds
    metadata: Optional[Dict[str, str]] = None
    if_not_exists: bool = False
    if_exists: bool = False


@dataclass
class ListOptions:
    """Options for listing keys."""
    prefix: Optional[str] = None
    cursor: Optional[str] = None
    limit: int = 100


@dataclass
class ListResult:
    """Result of listing keys."""
    entries: List[KeyValueEntry]
    cursor: Optional[str] = None
    has_more: bool = False


# ==================== Document Store Types ====================

@dataclass
class Document:
    """A document with metadata."""
    id: str
    data: Dict[str, Any]
    created_at: int
    updated_at: int
    version: int
    metadata: Optional[Dict[str, str]] = None


@dataclass
class QueryOptions:
    """Query options for document store."""
    filter: Optional[Dict[str, Any]] = None
    sort: Optional[Dict[str, SortOrder]] = None
    skip: int = 0
    limit: int = 100
    projection: Optional[List[str]] = None


@dataclass
class QueryResult:
    """Result of a document query."""
    documents: List[Document]
    total: int
    has_more: bool


# ==================== Vector Store Types ====================

@dataclass
class VectorEntry:
    """A vector entry."""
    id: str
    vector: List[float]
    metadata: Optional[Dict[str, Any]] = None
    content: Optional[str] = None


@dataclass
class SearchOptions:
    """Options for vector search."""
    namespace: Optional[str] = None
    top_k: int = 10
    filter: Optional[Dict[str, Any]] = None
    include_metadata: bool = True
    include_vectors: bool = False
    min_score: Optional[float] = None


@dataclass
class SearchResult:
    """Result of a vector search."""
    id: str
    score: float
    vector: Optional[List[float]] = None
    metadata: Optional[Dict[str, Any]] = None
    content: Optional[str] = None


@dataclass
class VectorCollectionConfig:
    """Configuration for a vector collection."""
    name: str
    dimension: int
    metric: DistanceMetric = DistanceMetric.COSINE
    index_type: str = "hnsw"


@dataclass
class VectorCollectionStats:
    """Statistics for a vector collection."""
    name: str
    vector_count: int
    dimension: int
    index_size: int


# ==================== Time Series Types ====================

@dataclass
class DataPoint:
    """A time series data point."""
    timestamp: int
    value: float
    tags: Optional[Dict[str, str]] = None


@dataclass
class TimeRange:
    """Time range for queries."""
    start: Union[int, datetime, str]
    end: Union[int, datetime, str]


@dataclass
class TimeSeriesQueryOptions:
    """Options for time series queries."""
    tags: Optional[Dict[str, str]] = None
    aggregation: Optional[Aggregation] = None
    interval: Optional[str] = None  # e.g., "1m", "5m", "1h"
    fill: Optional[Union[str, float]] = None
    limit: Optional[int] = None


@dataclass
class TimeSeriesResult:
    """Result of a time series query."""
    series: str
    points: List[DataPoint]
    statistics: Optional[Dict[str, float]] = None


@dataclass
class SeriesInfo:
    """Information about a time series."""
    name: str
    tags: List[str]
    retention_days: int
    point_count: int


# ==================== Database Stats ====================

@dataclass
class DatabaseStats:
    """Overall database statistics."""
    kv_entries: int
    document_count: int
    vector_count: int
    timeseries_points: int
    storage_used: int
    storage_limit: int


# ==================== Errors ====================

class DatabaseError(Exception):
    """Base exception for database errors."""

    def __init__(self, message: str, code: Optional[str] = None, status_code: Optional[int] = None):
        super().__init__(message)
        self.code = code
        self.status_code = status_code


class DocumentNotFoundError(DatabaseError):
    """Raised when a document is not found."""

    def __init__(self, collection: str, id: str):
        super().__init__(f"Document not found: {collection}/{id}", "DOCUMENT_NOT_FOUND", 404)


class KeyNotFoundError(DatabaseError):
    """Raised when a key is not found."""

    def __init__(self, key: str):
        super().__init__(f"Key not found: {key}", "KEY_NOT_FOUND", 404)
