"""Genosis SDK type definitions."""

from __future__ import annotations

from typing import Any, Callable, Generic, Literal, Optional, TypeVar

try:
    from typing import TypedDict
except ImportError:
    from typing_extensions import TypedDict  # type: ignore[assignment]

# ── Config ───────────────────────────────────────────────────────────────────

Provider = Literal["anthropic", "openai", "google"]
Tier = Literal["starter", "growth", "enterprise"]
ApiKeyScope = Literal["sdk:optimize", "api:read", "api:configure"]
OptimizationStatus = Literal["pending", "running", "completed", "failed", "none"]

R = TypeVar("R")


class CallResult(Generic[R]):
    """Result returned by call()."""

    def __init__(self, response: R, memoized: bool) -> None:
        self.response = response
        self.memoized = memoized

    def __repr__(self) -> str:
        return f"CallResult(memoized={self.memoized})"


# ── Account ──────────────────────────────────────────────────────────────────


class Account(TypedDict):
    id: str
    name: str
    tier: str
    created_at: str


class AccountUsage(TypedDict):
    period_start: str
    period_end: str
    total_requests: int


class ApiKey(TypedDict):
    id: str
    name: str
    key_prefix: str
    scopes: list[str]
    last_used_at: Optional[str]
    revoked_at: Optional[str]
    created_at: str


class CreatedApiKey(TypedDict):
    id: str
    name: str
    key_prefix: str
    scopes: list[str]
    last_used_at: Optional[str]
    revoked_at: Optional[str]
    created_at: str
    key: str  # Full key, only returned on creation


# ── Manifest ─────────────────────────────────────────────────────────────────


class CacheTrainEntry(TypedDict):
    hash: str
    tokens: int
    priority: float
    position: int


class OptimizationSummary(TypedDict):
    cache_discount_pct: float
    baseline_cost_per_request: float
    optimized_cost_per_request: float


class MemoizationCandidate(TypedDict):
    fingerprint: str
    ttl_seconds: int
    block_hashes: list[str]
    estimated_savings_per_hit: float


class MemoizationSection(TypedDict):
    enabled: bool
    max_ttl_seconds: int
    candidates: list[MemoizationCandidate]


class ModeSection(TypedDict, total=False):
    mode: str
    suspend_memoization: bool
    telemetry_interval_override: int
    reason: str
    since: str


class AnthropicHints(TypedDict, total=False):
    breakpoint_positions: list[int]
    min_breakpoint_spacing: int
    cache_type: str


class ProviderHints(TypedDict, total=False):
    anthropic: AnthropicHints
    openai: dict[str, Any]
    google: dict[str, Any]


class CacheManifest(TypedDict, total=False):
    manifest_version: str
    customer_id: str
    generated_at: str
    expires_at: str
    signature: str
    provider: str
    model: str
    cache_train: list[CacheTrainEntry]
    used_tokens: int
    optimization_summary: OptimizationSummary
    memoization: MemoizationSection
    mode: ModeSection
    provider_hints: ProviderHints


class ManifestResponse(TypedDict):
    data: Optional[CacheManifest]
    etag: Optional[str]


class ManifestHistoryEntry(TypedDict):
    id: str
    manifest_version: str
    provider: str
    model: str
    is_active: bool
    created_at: str


class ManifestsListEntry(TypedDict):
    provider: str
    model: str
    manifest_version: str
    generated_at: str
    expires_at: Optional[str]
    cache_train_count: int
    used_tokens: int


# ── Optimization ─────────────────────────────────────────────────────────────


class OptimizationResult(TypedDict):
    optimization_run_id: str
    status: str
    provider: str
    model: str
    cache_discount_pct: float
    blocks_cached: int
    manifest_version: str


class OptimizationStatusResponse(TypedDict, total=False):
    id: str
    status: str
    provider: str
    model: str
    started_at: Optional[str]
    completed_at: Optional[str]
    error: Optional[str]
    message: str


class OptimizationResults(TypedDict):
    baseline_daily_cost: float
    optimized_daily_cost: float
    cache_discount_pct: float
    blocks_in_cache: int
    blocks_total: int


class OptimizationResultsResponse(TypedDict):
    id: str
    status: str
    provider: str
    model: str
    results: Optional[OptimizationResults]
    started_at: str
    completed_at: str


# ── Telemetry ─────────────────────────────────────────────────────────────────


class TelemetrySummary(TypedDict):
    total_requests: int
    total_cost: float
    total_savings: float
    savings_pct: float
    avg_cost_per_request: float
    avg_latency_ms: float
    period_start: str
    period_end: str


class CostBreakdownEntry(TypedDict):
    date: str
    total_cost: float
    cached_cost: float
    uncached_cost: float
    output_cost: float
    request_count: int


class BlockFrequency(TypedDict):
    hash: str
    tokens: int
    count: int
    frequency: float
    cache_hit_rate: float


# ── Internal ──────────────────────────────────────────────────────────────────


class _TelemetryBlock(TypedDict):
    hash: str
    tokens: int
    cached: bool
    position: int


class _TelemetryUsage(TypedDict):
    input_tokens: int
    output_tokens: int
    cache_write_tokens: int
    cache_read_tokens: int


class _TelemetryEvent(TypedDict, total=False):
    event_id: str
    timestamp: str
    model: str
    provider: str
    blocks: list[_TelemetryBlock]
    latency_ms: dict[str, int]
    manifest_version: Optional[str]
    manifest_token: Optional[str]
    usage: _TelemetryUsage
    fingerprint: Optional[str]
