from __future__ import annotations

from dataiku import Folder

from backends.explorer.connections.db_config_scanner import DbConfigScanner
from backends.explorer.connections.kuzu.db_handler_factory import KuzuDbHandlerFactory
from backends.explorer.connections.neo4j.db_handler_factory import Neo4jDbHandlerFactory
from backends.explorer.metadata.metadata_manager import ExplorerMetadataManager
from graph.connections.db_handler import DbHandler
from graph.connections.neo4j.preset import Neo4jPresetConfig
from solutions.graph.models import DbType, ExplorerMetadata


def get_db_handler_from_snapshot(input_db_folder: Folder, snapshot_id: str, neo4j_configuration: Neo4jPresetConfig | None = None) -> DbHandler:
    explorer_metadata = ExplorerMetadataManager([input_db_folder])
    db_type = explorer_metadata.db_config_scanner.get_db_type(snapshot_id)
    db_folder = explorer_metadata.db_config_scanner.get_db_folder_by_snapshot_id(snapshot_id)

    if db_type == "kuzu":
        return KuzuDbHandlerFactory(db_folder, snapshot_id).get_db_handler()
    elif db_type == "neo4j":
        if not neo4j_configuration:
            raise ValueError("No Neo4j configuration provided")
        return Neo4jDbHandlerFactory(db_folder, snapshot_id, neo4j_configuration).get_db_handler()
    else:
        raise ValueError(f"Unknown database type '{db_type}' for snapshot {snapshot_id}")


def get_metadata_from_folder(db_folder: Folder, neo4j_configuration: Neo4jPresetConfig | None = None) -> ExplorerMetadata:
    db_config_scanner = DbConfigScanner([db_folder])
    graph_id_list = db_config_scanner.get_snapshot_ids()

    if not graph_id_list:
        raise ValueError("No graph database found in the input folder.")
    if len(graph_id_list) > 1:
        raise ValueError("Multiple graph databases found in the input folder, please select a folder with a single graph.")
    
    graph_id = graph_id_list[0]

    explorer_metadata = ExplorerMetadataManager([db_folder])
    db_handler = get_db_handler_from_snapshot(db_folder, graph_id, neo4j_configuration)
    snapshot_metadata = explorer_metadata.get_snapshot_metadata(graph_id, db_handler)

    return snapshot_metadata

def get_database_name_from_folder(db_folder: Folder) -> str:
    db_config_scanner = DbConfigScanner([db_folder])
    graph_id_list = db_config_scanner.get_snapshot_ids()

    if not graph_id_list:
        raise ValueError("No graph database found in the input folder.")
    if len(graph_id_list) > 1:
        raise ValueError("Multiple graph databases found in the input folder, please select a folder with a single graph.")

    graph_id = graph_id_list[0]
    db_type = db_config_scanner.get_db_type(graph_id)

    if db_type == "kuzu":
        return graph_id
    elif db_type == "neo4j":
        name = db_config_scanner.get_db_name(graph_id)
        if not name:
            raise ValueError(f"No database name found for Neo4j snapshot '{graph_id}'.")
        return name
    else:
        raise ValueError(f"Unknown database type '{db_type}' for snapshot {graph_id}.")

def get_database_type_from_folder(db_folder: Folder) -> DbType:
    db_config_scanner = DbConfigScanner([db_folder])
    graph_id_list = db_config_scanner.get_snapshot_ids()

    if not graph_id_list:
        raise ValueError("No graph database found in the input folder.")
    if len(graph_id_list) > 1:
        raise ValueError("Multiple graph databases found in the input folder, please select a folder with a single graph.")

    return db_config_scanner.get_db_type(graph_id_list[0])