from __future__ import annotations

import logging

from flask import Blueprint, Response

from backends.explorer.metadata.metadata_manager import ExplorerMetadataManager
from backends.explorer.utils.connections import get_webapp_db_handler, with_db_instance
from backends.shared.params import ComputeAdjacentNodeGroupInfoParams, GetAdjacentNodesParams
from backends.shared.queries import compute_adjacent_node_groups_info, compute_total_counts, get_adjacent_nodes
from backends.utils import return_ok, validate_params
from graph.connections.db_instance import DbInstance

logger = logging.getLogger(__name__)

graph_queries = Blueprint("graph_queries", __name__, url_prefix="/queries")


@graph_queries.route("/<snapshot_id>/computeAdjacentNodeGroupsInfo", methods=["POST"])
@validate_params(ComputeAdjacentNodeGroupInfoParams)
@with_db_instance
def get_adjacent_node_groups(
    db_instance: DbInstance,
    params: ComputeAdjacentNodeGroupInfoParams,
    snapshot_id: str,
) -> Response:
    """
    Computes summary information for adjacent node groups of a selection of nodes.

    Args:
        db_instance (DbInstance): Injected database instance.
        params (ComputeAdjacentNodeGroupInfoParams): Validated parameters.
        snapshot_id (str): The ID of the snapshot to query.

    Returns:
        dict: OK response with adjacency group information.
    """
    return return_ok(compute_adjacent_node_groups_info(db_instance, params))


@graph_queries.route("/<snapshot_id>/getAdjacentNodes", methods=["POST"])
@validate_params(GetAdjacentNodesParams)
@with_db_instance
def get_adjacent_nodes_endpoint(
    db_instance: DbInstance,
    params: GetAdjacentNodesParams,
    snapshot_id: str,
) -> Response:
    """
    Retrieves adjacent nodes for a given selection based on filters.

    Args:
        db_instance (DbInstance): Injected database instance.
        params (GetAdjacentNodesParams): Validated parameters.
        snapshot_id (str): The ID of the snapshot to query.

    Returns:
        dict: OK response with the list of adjacent nodes and edges.
    """
    db_handler, conn_info_registry = get_webapp_db_handler(snapshot_id)
    graph_manager = ExplorerMetadataManager(conn_info_registry)
    explorer_metadata = graph_manager.get_snapshot_metadata(snapshot_id, db_handler)
    
    node_definitions = explorer_metadata["node_definitions"]
    edge_definitions = explorer_metadata["edge_definitions"]
    
    return return_ok(get_adjacent_nodes(db_instance, params, node_definitions, edge_definitions))


@graph_queries.route("/<snapshot_id>/getTotalCounts", methods=["GET"])
@with_db_instance
def get_total_counts(db_instance: DbInstance, snapshot_id: str) -> Response:
    """
    Retrieves the total count of nodes and edges in the graph.

    Args:
        db_instance (DbInstance): Injected database instance.
        snapshot_id (str): The ID of the snapshot to query.

    Returns:
        dict: OK response with total counts.
    """
    return return_ok(compute_total_counts(db_instance))
