"""Build a memory snapshot from current store state.

The snapshotter is side-effect-free: returns a :class:`MemorySnapshot`.
Persistence is the caller's job (via :func:`arborist.memory.store_snapshot`).
"""

from __future__ import annotations

import sqlite3
from typing import Iterable, Optional

from arborist.memory.canonical import (
    SCHEMA_VERSION,
    BranchSummary,
    MemorySnapshot,
)
from arborist.memory.projections import (
    DEFAULT_BRANCHES,
    project_failure_motif_violations,
)


def _parent_memory_root(conn: sqlite3.Connection) -> Optional[str]:
    row = conn.execute(
        "SELECT memory_root FROM memory_records "
        "WHERE state = 'live' "
        "ORDER BY created_at DESC LIMIT 1"
    ).fetchone()
    if row is None:
        return None
    return row["memory_root"]


def snapshot(
    conn: sqlite3.Connection,
    *,
    branches: Optional[Iterable] = None,
) -> MemorySnapshot:
    """Build a :class:`MemorySnapshot` over current state.

    Parameters
    ----------
    conn:
        Read-write SQLite connection.
    branches:
        Iterable of branch projection functions. Defaults to
        :data:`DEFAULT_BRANCHES`. Each function takes the connection
        and an optional ``high_water`` kwarg and returns either a
        :class:`BranchSummary` or a ``(BranchSummary, latest_hash)``
        tuple.
    """
    parent = _parent_memory_root(conn)

    if branches is None:
        branches = DEFAULT_BRANCHES

    summaries: list[BranchSummary] = []
    high_water = "genesis"
    for fn in branches:
        # Some projections also return the latest event hash they saw.
        result = fn(conn)
        if isinstance(result, tuple):
            summary, latest_hash = result
            high_water = latest_hash
        else:
            summary = result
        summaries.append(summary)

    # If no branch surfaced a high-water, look one up directly.
    if high_water == "genesis":
        latest = conn.execute(
            "SELECT event_hash FROM audit_events ORDER BY seq DESC LIMIT 1"
        ).fetchone()
        high_water = latest["event_hash"] if latest else "genesis"

    return MemorySnapshot(
        schema_version=SCHEMA_VERSION,
        parent_memory_root=parent,
        audit_events_high_water=high_water,
        branches=tuple(summaries),
    )
