"""
cortex/storage/_helpers.py — Shared helpers for storage mixins.

Utility functions and row→dataclass converters used by both the main
SQLiteAdapter and all query mixin classes.
"""

from __future__ import annotations

import hashlib
import struct
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

import aiosqlite

from cortex.types import (
    BrainGraphEdge,
    BrainGraphIndex,
    BrainGraphNode,
    ClaimProvenance,
    CornerstoneMemory,
    Entity,
    EntityAlias,
    EpisodeEvent,
    EvolutionProposal,
    FTSResult,
    MemoryEdge,
    MemoryFeedback,
    Peer,
    ProcedureMemory,
    SemanticClaim,
    SessionRecord,
    VectorResult,
)


def _now() -> str:
    """Return current UTC time as ISO 8601 string with millisecond precision."""
    return datetime.now(timezone.utc).isoformat(timespec="milliseconds")


def _sha256(text: str) -> str:
    return hashlib.sha256(text.encode()).hexdigest()


def _pack_floats(v: List[float]) -> bytes:
    """Pack a list of floats into a raw bytes blob (little-endian float32)."""
    return struct.pack(f"{len(v)}f", *v)


def _unpack_floats(blob: bytes) -> List[float]:
    n = len(blob) // 4
    return list(struct.unpack(f"{n}f", blob))


def _cosine_similarity(a: List[float], b: List[float]) -> float:
    """Pure-Python cosine similarity (fallback when numpy unavailable)."""
    dot = sum(x * y for x, y in zip(a, b))
    norm_a = sum(x * x for x in a) ** 0.5
    norm_b = sum(y * y for y in b) ** 0.5
    if norm_a == 0 or norm_b == 0:
        return 0.0
    return dot / (norm_a * norm_b)


# ---------------------------------------------------------------------------
# Row → dataclass helpers
# ---------------------------------------------------------------------------

def _row_to_entity(row: aiosqlite.Row) -> Entity:
    d = dict(row)
    return Entity(**{k: d[k] for k in Entity.__dataclass_fields__ if k in d})


def _row_to_entity_alias(row: aiosqlite.Row) -> EntityAlias:
    d = dict(row)
    return EntityAlias(**{k: d[k] for k in EntityAlias.__dataclass_fields__ if k in d})


def _row_to_cornerstone(row: aiosqlite.Row) -> CornerstoneMemory:
    d = dict(row)
    return CornerstoneMemory(**{k: d[k] for k in CornerstoneMemory.__dataclass_fields__ if k in d})


def _row_to_session(row: aiosqlite.Row) -> SessionRecord:
    d = dict(row)
    return SessionRecord(**{k: d[k] for k in SessionRecord.__dataclass_fields__ if k in d})


def _row_to_episode(row: aiosqlite.Row) -> EpisodeEvent:
    d = dict(row)
    return EpisodeEvent(**{k: d[k] for k in EpisodeEvent.__dataclass_fields__ if k in d})


def _row_to_claim(row: aiosqlite.Row) -> SemanticClaim:
    d = dict(row)
    return SemanticClaim(**{k: d[k] for k in SemanticClaim.__dataclass_fields__ if k in d})


def _row_to_provenance(row: aiosqlite.Row) -> ClaimProvenance:
    d = dict(row)
    return ClaimProvenance(**{k: d[k] for k in ClaimProvenance.__dataclass_fields__ if k in d})


def _row_to_edge(row: aiosqlite.Row) -> MemoryEdge:
    d = dict(row)
    return MemoryEdge(**{k: d[k] for k in MemoryEdge.__dataclass_fields__ if k in d})


def _row_to_brain_graph(row: aiosqlite.Row) -> BrainGraphIndex:
    d = dict(row)
    return BrainGraphIndex(**{k: d[k] for k in BrainGraphIndex.__dataclass_fields__ if k in d})


def _row_to_brain_node(row: aiosqlite.Row) -> BrainGraphNode:
    d = dict(row)
    return BrainGraphNode(**{k: d[k] for k in BrainGraphNode.__dataclass_fields__ if k in d})


def _row_to_brain_edge(row: aiosqlite.Row) -> BrainGraphEdge:
    d = dict(row)
    return BrainGraphEdge(**{k: d[k] for k in BrainGraphEdge.__dataclass_fields__ if k in d})


def _row_to_feedback(row: aiosqlite.Row) -> MemoryFeedback:
    d = dict(row)
    return MemoryFeedback(**{k: d[k] for k in MemoryFeedback.__dataclass_fields__ if k in d})


def _row_to_evolution_proposal(row: aiosqlite.Row) -> EvolutionProposal:
    d = dict(row)
    return EvolutionProposal(**{k: d[k] for k in EvolutionProposal.__dataclass_fields__ if k in d})
