#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
# See LICENSE file for details.
"""
Shared graph helper functions used by both knowledge_graph_query.py and graph_query_ext.py.

Extracted to break the circular import between those two modules.
Contains: _get_conn, _sqlite_has_data, _find_nodes_sql, _load_graph_json, _find_matching_nodes_json
"""

from pulse.core.brain_utils import GRAPH_FILE, load_json_dict, search_relevance


def _get_conn():
    """Get SQLite connection, returns None if unavailable."""
    try:
        from pulse.core.brain_db import get_conn
        return get_conn()
    except Exception:
        return None


def _sqlite_has_data(conn) -> bool:
    """Check if SQLite graph tables have data."""
    if conn is None:
        return False
    try:
        row = conn.execute("SELECT COUNT(*) as c FROM graph_nodes").fetchone()
        return row and row["c"] > 0
    except Exception:
        return False


def _find_nodes_sql(conn, query: str, limit: int = 10) -> list:
    """Find matching nodes via LIKE + text_similarity fallback."""
    # Split multi-word queries into AND-chained LIKE clauses
    words = [w for w in query.strip().split() if len(w) > 2]
    if not words:
        words = [query.strip()]
    conditions = " AND ".join("text LIKE ?" for _ in words)
    params = [f"%{w}%" for w in words] + [limit]
    rows = conn.execute(
        f"SELECT id, type, text, confidence FROM graph_nodes WHERE {conditions} LIMIT ?",
        params
    ).fetchall()
    if rows:
        return [dict(r) for r in rows]

    # Fallback: load candidates and score
    candidates = conn.execute(
        "SELECT id, type, text, confidence FROM graph_nodes LIMIT 1000"
    ).fetchall()
    scored = []
    for r in candidates:
        sim = search_relevance(query, r["text"] or "")
        if sim >= 0.25:
            scored.append((dict(r), sim))
    scored.sort(key=lambda x: -x[1])
    return [r for r, _ in scored[:limit]]


def _load_graph_json() -> dict:
    """Load graph from JSON file (legacy fallback)."""
    if not GRAPH_FILE.exists():
        return {"nodes": {}, "edges": []}
    return load_json_dict(GRAPH_FILE)


def _find_matching_nodes_json(query: str, graph: dict, threshold: float = 0.25) -> list:
    """Find graph nodes matching query by text similarity (JSON fallback)."""
    matches = []
    for nid, node in graph.get("nodes", {}).items():
        sim = search_relevance(query, node.get("text", ""))
        if sim >= threshold:
            matches.append((nid, sim))
    matches.sort(key=lambda x: -x[1])
    return [nid for nid, _ in matches[:10]]
