import os
from typing import Dict, Any
from modules.logger_tool import initialise_logger
import modules.database.tools.neo4j_driver_tools as driver_tools
import modules.database.tools.neo4j_session_tools as session_tools

class Neo4jService:
    """Service for managing Neo4j database operations"""
    
    def __init__(self):
        self.logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
        self.driver = driver_tools.get_driver()

    def check_database_exists(self, database_name: str) -> Dict[str, Any]:
        """Check if a Neo4j database exists
        
        Args:
            database_name (str): Name of the database to check
            
        Returns:
            Dict[str, Any]: Result containing existence status and operation status
        """
        try:
            with self.driver.session() as session:
                result = session.run(
                    "SHOW DATABASES YIELD name WHERE name = $name",
                    name=database_name
                )
                exists = bool(result.single())
                return {
                    "exists": exists,
                    "status": "success"
                }
        except Exception as e:
            self.logger.error(f"Error checking database {database_name}: {str(e)}")
            return {
                "exists": False,
                "status": "error",
                "message": str(e)
            }

    def create_database(self, db_name: str) -> Dict[str, Any]:
        """Creates a Neo4j database with the given name
        
        Args:
            db_name (str): Name of the database to create
            
        Returns:
            Dict[str, Any]: Result containing operation status and message
        """
        try:
            # First check if database exists
            exists_result = self.check_database_exists(db_name)
            if exists_result["status"] == "error":
                return exists_result
                
            if not exists_result["exists"]:
                with self.driver.session() as session:
                    session_tools.create_database(session, db_name)
                    self.logger.info(f"Created database {db_name}")
                    return {
                        "status": "success",
                        "message": f"Database {db_name} created successfully"
                    }
            else:
                self.logger.info(f"Database {db_name} already exists")
                return {
                    "status": "success", 
                    "message": f"Database {db_name} already exists"
                }
                
        except Exception as e:
            self.logger.error(f"Error creating database {db_name}: {str(e)}")
            return {"status": "error", "message": str(e)}

    def initialize_schema(self, database_name: str) -> Dict[str, Any]:
        """Initialize Neo4j schema (constraints and indexes) for a database
        
        Args:
            database_name (str): Name of the database to initialize schema for
            
        Returns:
            Dict[str, Any]: Result containing operation status and message
        """
        try:
            with self.driver.session(database=database_name) as session:
                # Create constraints
                constraints = [
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:School) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Department) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Subject) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:YearGroup) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Class) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Teacher) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Student) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Calendar) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Term) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Week) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Day) REQUIRE n.uuid_string IS UNIQUE",
                    "CREATE CONSTRAINT IF NOT EXISTS FOR (n:Period) REQUIRE n.uuid_string IS UNIQUE"
                ]
                
                # Create indexes
                indexes = [
                    "CREATE INDEX IF NOT EXISTS FOR (n:School) ON (n.urn)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Department) ON (n.department_name)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Subject) ON (n.subject_name)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:YearGroup) ON (n.year_group)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Class) ON (n.class_name)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Teacher) ON (n.email)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Student) ON (n.email)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Calendar) ON (n.calendar_name)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Term) ON (n.term_name)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Week) ON (n.week_number)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Day) ON (n.date)",
                    "CREATE INDEX IF NOT EXISTS FOR (n:Period) ON (n.period_name)"
                ]
                
                # Execute all constraints
                for constraint in constraints:
                    session.run(constraint)
                
                # Execute all indexes
                for index in indexes:
                    session.run(index)
                
                self.logger.info(f"Successfully initialized schema for database {database_name}")
                return {
                    "status": "success",
                    "message": f"Schema initialized successfully for database {database_name}"
                }
                
        except Exception as e:
            self.logger.error(f"Error initializing schema for database {database_name}: {str(e)}")
            return {
                "status": "error",
                "message": str(e)
            }

    def delete_database(self, db_name: str) -> Dict[str, Any]:
        """Deletes a Neo4j database
        
        Args:
            db_name (str): Name of the database to delete
            
        Returns:
            Dict[str, Any]: Result containing operation status and message
        """
        try:
            exists_result = self.check_database_exists(db_name)
            if exists_result["status"] == "error":
                return exists_result
                
            if exists_result["exists"]:
                with self.driver.session() as session:
                    session_tools.reset_database_in_session(session)
                    self.logger.info(f"Deleted database {db_name}")
                    return {
                        "status": "success",
                        "message": f"Database {db_name} deleted successfully"
                    }
            else:
                return {
                    "status": "success",
                    "message": f"Database {db_name} does not exist"
                }
                
        except Exception as e:
            self.logger.error(f"Error deleting database {db_name}: {str(e)}")
            return {"status": "error", "message": str(e)}

    def check_node_exists(self, database_name: str, node_label: str) -> Dict[str, Any]:
        """Check if any nodes with the given label exist in the specified database
        
        Args:
            database_name (str): Name of the database to check
            node_label (str): Label of the node type to check for
            
        Returns:
            Dict[str, Any]: Result containing count and operation status
        """
        try:
            with self.driver.session(database=database_name) as session:
                nodes = session_tools.find_nodes_by_label(session, node_label)
                count = len(nodes)
                return {
                    "exists": count > 0,
                    "count": count,
                    "status": "success"
                }
        except Exception as e:
            self.logger.error(f"Error checking for {node_label} nodes in database {database_name}: {str(e)}")
            return {
                "exists": False,
                "count": 0,
                "status": "error",
                "message": str(e)
            }
