import os
from modules.logger_tool import initialise_logger
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
import modules.database.tools.neo4j_driver_tools as driver_tools
import modules.database.tools.neo4j_session_tools as session_tools
from datetime import datetime, timedelta
from typing import List, Optional, Dict, Any

def get_static_nodes(context: str, db_name: str) -> List[Dict[str, Any]]:
    """Get static nodes for a specific context."""
    if context == 'workers':
        # For workers context, show teacher node first, then timetables and classes
        query = """
        MATCH (t:Teacher)
        RETURN DISTINCT {
            id: t.uuid_string,
            path: t.node_storage_path,
            label: t.teacher_name_formal,
            type: 'Teacher',
            isStatic: true,
            order: 0,
            section: 'Root'
        } as node
        UNION ALL
        MATCH (t:UserTeacherTimetable)
        RETURN DISTINCT {
            id: t.uuid_string,
            path: t.node_storage_path,
            label: t.name,
            type: 'UserTeacherTimetable',
            isStatic: true,
            order: 1,
            section: 'Timetables'
        } as node
        UNION ALL
        MATCH (t:UserTeacherTimetable)-[:HAS_CLASS]->(c:Class)
        RETURN DISTINCT {
            id: c.uuid_string,
            path: c.node_storage_path,
            label: c.name,
            type: 'Class',
            isStatic: true,
            order: 2,
            section: 'Classes'
        } as node
        """
    elif context == 'user':
        # For user context, show the user node
        query = """
        MATCH (u:User)
        RETURN DISTINCT {
            id: u.uuid_string,
            path: u.node_storage_path,
            label: u.user_name,
            type: 'User',
            isStatic: true,
            order: 0,
            section: 'Root'
        } as node
        """
    else:
        # For calendar context, show today's calendar node first, then other calendar nodes
        today = datetime.now().strftime("%Y-%m-%d")
        query = """
        MATCH (n:Calendar)
        WITH n, 
        CASE 
            WHEN date($today) >= date(n.start_date) AND date($today) <= date(n.end_date) 
            THEN 0 
            ELSE 1 
        END as nodeOrder
        RETURN DISTINCT {
            id: n.uuid_string,
            path: n.node_storage_path,
            label: n.name,
            type: 'Calendar',
            isStatic: true,
            order: nodeOrder,
            section: CASE nodeOrder 
                WHEN 0 THEN 'Today'
                ELSE 'Calendar'
            END
        } as node
        ORDER BY node.order, node.label
        """ 

    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, today=datetime.now().strftime("%Y-%m-%d"))
            return [record["node"] for record in result]
    except Exception as e:
        logger.error(f"Error getting static nodes: {str(e)}")
        return []

def get_today_calendar_node(db_name: str) -> Optional[Dict[str, Any]]:
    """Get today's calendar node."""
    today = datetime.now().strftime("%Y-%m-%d")
    query = """
    MATCH (n:Calendar)
    WHERE date($today) >= date(n.start_date) AND date($today) <= date(n.end_date)
    RETURN n.uuid_string as id, n.path as path, n.name as label, 
           'Calendar' as type
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, today=today)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting today's calendar node: {str(e)}")
        return None

def get_relative_calendar_node(day_offset: int, db_name: str) -> Optional[Dict[str, Any]]:
    """Get calendar node relative to today."""
    target_date = (datetime.now() + timedelta(days=day_offset)).strftime("%Y-%m-%d")
    query = """
    MATCH (n:Calendar)
    WHERE date($target_date) >= date(n.start_date) AND date($target_date) <= date(n.end_date)
    RETURN n.uuid_string as id, n.node_storage_path as path, n.name as label, 
           'Calendar' as type
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, target_date=target_date)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting relative calendar node: {str(e)}")
        return None

def get_next_month_node(db_name: str) -> Optional[Dict[str, Any]]:
    """Get next month's calendar node."""
    next_month_start = (datetime.now().replace(day=1) + timedelta(days=32)).replace(day=1).strftime("%Y-%m-%d")
    query = """
    MATCH (n:Calendar)
    WHERE date($next_month_start) >= date(n.start_date) AND date($next_month_start) <= date(n.end_date)
    RETURN n.uuid_string as id, n.node_storage_path as path, n.name as label, 
           'Calendar' as type
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, next_month_start=next_month_start)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting next month node: {str(e)}")
        return None

def get_previous_month_node(db_name: str) -> Optional[Dict[str, Any]]:
    """Get previous month's calendar node."""
    prev_month_start = (datetime.now().replace(day=1) - timedelta(days=1)).replace(day=1).strftime("%Y-%m-%d")
    query = """
    MATCH (n:Calendar)
    WHERE date($prev_month_start) >= date(n.start_date) AND date($prev_month_start) <= date(n.end_date)
    RETURN n.uuid_string as id, n.node_storage_path as path, n.name as label, 
           'Calendar' as type
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, prev_month_start=prev_month_start)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting previous month node: {str(e)}")
        return None

def get_user_timetables(db_name: str) -> List[Dict[str, Any]]:
    """Get user's timetables."""
    query = """
    MATCH (t:UserTeacherTimetable)
    RETURN t.uuid_string as id, t.node_storage_path as path, t.name as label, 
           'UserTeacherTimetable' as type
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query)
            return [dict(record) for record in result]
    except Exception as e:
        logger.error(f"Error getting user timetables: {str(e)}")
        return []

def get_timetable_classes(timetable_id: str, db_name: str) -> List[Dict[str, Any]]:
    """Get classes for a timetable."""
    query = """
    MATCH (t:UserTeacherTimetable {uuid_string: $timetable_id})-[:HAS_CLASS]->(c:Class)
    RETURN c.uuid_string as id, c.node_storage_path as path, c.name as label, 
           'Class' as type
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, timetable_id=timetable_id)
            return [dict(record) for record in result]
    except Exception as e:
        logger.error(f"Error getting timetable classes: {str(e)}")
        return []

def get_next_lesson(class_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get next lesson for a class."""
    now = datetime.now().strftime("%Y-%m-%d %H:%M")
    query = """
    MATCH (c:Class {uuid_string: $class_id})-[:HAS_LESSON]->(l:Lesson)
    WHERE l.start_time > $now
    RETURN l.uuid_string as id, l.node_storage_path as path, l.name as label, 
           'Lesson' as type
    ORDER BY l.start_time ASC
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, class_id=class_id, now=now)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting next lesson: {str(e)}")
        return None

def get_previous_lesson(class_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get previous lesson for a class."""
    now = datetime.now().strftime("%Y-%m-%d %H:%M")
    query = """
    MATCH (c:Class {uuid_string: $class_id})-[:HAS_LESSON]->(l:Lesson)
    WHERE l.start_time < $now
    RETURN l.uuid_string as id, l.path as path, l.name as label, 
           'Lesson' as type
    ORDER BY l.start_time DESC
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, class_id=class_id, now=now)
            record = result.single()
            return dict(record) if record else None
    except Exception as e:
        logger.error(f"Error getting previous lesson: {str(e)}")
        return None

def save_shared_snapshot(path: str, room_id: str, snapshot: Dict[str, Any]) -> bool:
    """Save snapshot to a shared room."""
    try:
        # Save the snapshot to the shared room's storage
        session_tools.save_tldraw_node_file(path, room_id, snapshot)
        return True
    except Exception as e:
        logger.error(f"Error saving shared snapshot: {str(e)}")
        return False

def get_connected_nodes_for_workers(node_id: str, db_name: str) -> List[Dict[str, Any]]:
    """Get connected nodes specific to the workers context."""
    query = """
    MATCH (n {uuid_string: $node_id})
    WITH n
    CALL {
        WITH n
        MATCH (n:UserTeacherTimetable)-[:HAS_CLASS]->(c:Class)
        RETURN c.uuid_string as id, c.node_storage_path as path, c.name as label, 
               'Class' as type
        UNION
        MATCH (n:Class)<-[:HAS_CLASS]-(t:UserTeacherTimetable)
        RETURN t.uuid_string as id, t.node_storage_path as path, t.name as label, 
               'UserTeacherTimetable' as type
        UNION
        MATCH (n:Class)-[:HAS_LESSON]->(l:Lesson)
        RETURN l.uuid_string as id, l.node_storage_path as path, l.name as label, 
               'Lesson' as type
    }
    RETURN DISTINCT id, path, label, type
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, node_id=node_id)
            return [dict(record) for record in result]
    except Exception as e:
        logger.error(f"Error getting connected nodes for workers: {str(e)}")
        return []

def get_connected_nodes(node_id: str, db_name: str, context: str = None) -> List[Dict[str, Any]]:
    """Get connected nodes based on context."""
    if context == 'workers':
        return get_connected_nodes_for_workers(node_id, db_name)
    
    # Default query for other contexts
    query = """
    MATCH (n {uuid_string: $node_id})-[r]-(connected)
    RETURN DISTINCT connected.uuid_string as id, connected.path as path, 
           connected.name as label, labels(connected)[0] as type
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, node_id=node_id)
            return [dict(record) for record in result]
    except Exception as e:
        logger.error(f"Error getting connected nodes: {str(e)}")
        return []

## Worker Navigation

def get_worker_structure(db_name: str) -> Dict[str, Any]:
    """Get the complete worker structure including schools, departments, timetables, classes, and lessons."""
    try:
        query = """
        // Match all worker-related nodes
        MATCH (s:School)
        OPTIONAL MATCH (s)-[:HAS_DEPARTMENT]->(d:Department)
        OPTIONAL MATCH (d)-[:HAS_TIMETABLE]->(t:UserTeacherTimetable)
        OPTIONAL MATCH (t)-[:HAS_CLASS]->(c:Class)
        OPTIONAL MATCH (c)-[:HAS_LESSON]->(l:TimetableLesson)
        WITH s, d, t, c, l
        ORDER BY s.school_name, d.department_code, t.name, c.class_code, l.start_time

        // Collect all nodes
        RETURN {
            schools: collect(DISTINCT {
                id: s.uuid_string,
                path: s.node_storage_path,
                name: s.school_name,
                __primarylabel__: 'School'
            }),
            departments: collect(DISTINCT {
                id: d.uuid_string,
                path: d.node_storage_path,
                code: d.department_code,
                school_id: s.uuid_string,
                __primarylabel__: 'Department'
            }),
            timetables: collect(DISTINCT {
                id: t.uuid_string,
                path: t.node_storage_path,
                name: t.name,
                department_id: d.uuid_string,
                __primarylabel__: 'UserTeacherTimetable'
            }),
            classes: collect(DISTINCT {
                id: c.uuid_string,
                path: c.node_storage_path,
                code: c.class_code,
                timetable_id: t.uuid_string,
                __primarylabel__: 'Class'
            }),
            lessons: collect(DISTINCT {
                id: l.uuid_string,
                path: l.node_storage_path,
                start_time: l.start_time,
                class_id: c.uuid_string,
                __primarylabel__: 'TimetableLesson'
            })
        } as structure
        """

        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query)
            record = result.single()
            if not record:
                logger.error('No worker structure found')
                return None
            
            return {
                "status": "success",
                "structure": record["structure"]
            }

    except Exception as e:
        logger.error(f"Error getting worker structure: {str(e)}")
        return None

def get_school_node(school_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get a specific school node."""
    query = """
    MATCH (s:School {uuid_string: $school_id})
    RETURN {
        id: s.uuid_string,
        path: s.node_storage_path,
        name: s.school_name,
        __primarylabel__: 'School'
    } as node
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, school_id=school_id)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting school node: {str(e)}")
        return None

def get_department_node(dept_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get a specific department node."""
    query = """
    MATCH (d:Department {uuid_string: $dept_id})
    RETURN {
        id: d.uuid_string,
        path: d.node_storage_path,
        code: d.department_code,
        __primarylabel__: 'Department'
    } as node
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, dept_id=dept_id)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting department node: {str(e)}")
        return None

def get_timetable_node(timetable_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get a specific timetable node."""
    query = """
    MATCH (t:UserTeacherTimetable {uuid_string: $timetable_id})
    RETURN {
        id: t.uuid_string,
        path: t.node_storage_path,
        name: t.name,
        __primarylabel__: 'UserTeacherTimetable'
    } as node
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, timetable_id=timetable_id)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting timetable node: {str(e)}")
        return None

def get_class_node(class_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get a specific class node."""
    query = """
    MATCH (c:Class {uuid_string: $class_id})
    RETURN {
        id: c.uuid_string,
        path: c.node_storage_path,
        code: c.class_code,
        __primarylabel__: 'Class'
    } as node
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, class_id=class_id)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting class node: {str(e)}")
        return None

def get_lesson_node(lesson_id: str, db_name: str) -> Optional[Dict[str, Any]]:
    """Get a specific lesson node."""
    query = """
    MATCH (l:TimetableLesson {uuid_string: $lesson_id})
    RETURN {
        id: l.uuid_string,
        path: l.node_storage_path,
        start_time: l.start_time,
        __primarylabel__: 'TimetableLesson'
    } as node
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, lesson_id=lesson_id)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting lesson node: {str(e)}")
        return None

def get_current_lesson(db_name: str) -> Optional[Dict[str, Any]]:
    """Get the current or next upcoming lesson."""
    now = datetime.now().strftime("%Y-%m-%d %H:%M")
    query = """
    MATCH (l:TimetableLesson)
    WHERE l.start_time >= $now
    RETURN {
        id: l.uuid_string,
        path: l.node_storage_path,
        start_time: l.start_time,
        __primarylabel__: 'TimetableLesson'
    } as node
    ORDER BY l.start_time ASC
    LIMIT 1
    """
    try:
        with driver_tools.get_session(database=db_name) as session:
            result = session.run(query, now=now)
            record = result.single()
            return record["node"] if record else None
    except Exception as e:
        logger.error(f"Error getting current lesson: {str(e)}")
        return None