from collections import deque
import heapq

def walk_back(start_id, n, query):
    visited = set()
    results = []
    queue = deque([(start_id, 0)])  # (dr_id, hops)

    query_vec = embed(query)  # Precompute embedding for semantic scoring

    while queue:
        dr_id, depth = queue.popleft()
        if dr_id in visited or depth > n:
            continue
        visited.add(dr_id)

        # Get metadata from RocksDB first, fallback to SQLite
        metadata = get_metadata(dr_id)
        if not metadata:
            continue

        # Score
        sim_score = cosine_similarity(query_vec, embed(metadata['statement']))
        dist_score = max(0, (n - depth) / n)  # Closer ancestors score higher
        constraint_penalty = -0.2 if metadata.get("blocked") else 0

        total_score = (0.6 * sim_score) + (0.3 * dist_score) + constraint_penalty
        heapq.heappush(results, (-total_score, metadata))  # Max-heap

        # Traverse ancestors
        for anc_id in get_ancestors(dr_id):
            queue.append((anc_id, depth + 1))

    # Return top results sorted
    sorted_results = [md for _, md in sorted(results)]
    cache_walk_results(start_id, n, query, sorted_results)
    return sorted_results


def get_metadata(dr_id):
    val = rocks.get(f"meta:{dr_id}")
    if val:
        return deserialize(val)

    # Fallback to SQLite
    row = sqlite_conn.execute("""
        SELECT statement, lifecycle_state, role_exposure, tags, timestamp
        FROM decisions WHERE id=?
    """, (dr_id,)).fetchone()
    if row:
        return {
            "id": dr_id,
            "statement": row[0],
            "lifecycle_state": row[1],
            "role_exposure": json.loads(row[2]),
            "tags": json.loads(row[3]),
            "timestamp": row[4]
        }
    return None


def get_ancestors(dr_id):
    val = rocks.get(f"rev:{dr_id}")
    if val:
        return deserialize(val)

    # Fallback to SQLite edges
    rows = sqlite_conn.execute("""
        SELECT source_id FROM edges
        WHERE target_id=? AND relation='influences'
    """, (dr_id,)).fetchall()
    return [r[0] for r in rows]


def cache_walk_results(start_id, n, query, results):
    cache_key = f"walkcache:{start_id}:{n}:{hash(query)}"
    rocks.put(cache_key, serialize(results))
