from __future__ import annotations

import logging
from pathlib import Path

from diskcache import Index
from neo4j import Driver

from backends.editor.utils.store import get_or_create_neo4j_db_instance_access_diskcache_dir
from graph.connections.db_instance import DbInstance
from graph.connections.kuzu.db_instance import DbReadWriteLock
from graph.connections.neo4j.db_connection import Neo4jConnection

logger = logging.getLogger(__name__)


class Neo4jDbInstance(DbInstance):
    def __init__(
        self,
        driver: Driver,
        database: str,
        readonly: bool,
        timeout_seconds: int | None = None,
    ) -> None:
        """
        Initialize Neo4j database instance.

        Args:
            driver: Neo4j driver instance (managed by Neo4DbHandler).
            database: Database name.
            readonly: Whether this instance should be read-only.
            timeout_seconds: Query timeout in seconds.
        """
        self.__driver = driver
        self.database = database
        self.readonly = readonly
        self.timeout_seconds = timeout_seconds

        diskcache_path = get_or_create_neo4j_db_instance_access_diskcache_dir()
        logger.debug(f"Initializing neo4j db instance access index with diskcache at {diskcache_path}.")
        self.read_write_lock = DbReadWriteLock(Index(diskcache_path))

    def open(self) -> None:
        self.read_write_lock.try_acquire_lock(self.get_db_path(), self.readonly)
        logger.debug(f"Neo4jDbInstance successfully opened.")

    def close(self) -> None:
        self.read_write_lock.release_lock(self.get_db_path(), self.readonly)
        logger.debug(f"Neo4jDbInstance successfully closed.")

    def get_db_path(self) -> Path:
        """Return a pseudo-path representing the Neo4j database name."""
        return Path(self.database)

    def exists(self) -> bool:
        """Check if Neo4j database is accessible."""
        try:
            with self.get_new_conn() as conn:
                conn.execute("RETURN 1")
                return True
        except Exception:
            logger.debug("Neo4j database is not accessible")
        return False

    def get_new_conn(self, timeout_seconds: int | None = None) -> Neo4jConnection:
        """
        Create a new Neo4j connection.

        Args:
            timeout_seconds: Override default timeout for this connection.

        Returns:
            Neo4jConnection instance.
        """
        timeout = timeout_seconds or self.timeout_seconds
        return Neo4jConnection(self.__driver, self.database, self.readonly, timeout)
