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.schemas.nodes.calendars as calendar_schemas
import modules.database.schemas.relationships.calendars as calendar_relationships
import modules.database.schemas.relationships.calendar_sequence as calendar_sequence_relationships
import modules.database.tools.supabase_storage_tools as storage_tools
import modules.database.tools.neontology_tools as neon
from datetime import timedelta, datetime

def create_calendar(db_name, start_date, end_date, time_chunk_node_length: int = None, storage_tools=None):
    """
    Create calendar structure with years, months, weeks, and days
    
    Args:
        db_name: Database name to create calendar in
        start_date: Start date for calendar
        end_date: End date for calendar
        time_chunk_node_length: Optional time chunk length in minutes
        storage_tools: Optional Supabase storage tools for generating storage paths
    
    Returns:
        dict: Dictionary containing created calendar nodes
    """
    logger.info(f"Creating calendar structure for {start_date} to {end_date} in database: {db_name}")
    
    logger.info(f"Initializing Neontology connection")
    neon.init_neontology_connection()

    created_years = {}
    created_months = {}
    created_weeks = {}
    created_days = {}

    last_year_node = None
    last_month_node = None
    last_week_node = None
    last_day_node = None

    calendar_nodes = {
        'calendar_year_nodes': [],
        'calendar_month_nodes': [],
        'calendar_week_nodes': [],
        'calendar_day_nodes': [],
        'calendar_time_chunk_nodes': []
    }

    current_date = start_date
    while current_date <= end_date:
        year = current_date.year
        month = current_date.month
        day = current_date.day
        iso_year, iso_week, iso_weekday = current_date.isocalendar()

        calendar_year_uuid_string = f"{year}"

        if year not in created_years:
            # Generate storage path for year node using Supabase Storage
            if storage_tools:
                year_dir_created, node_storage_path = storage_tools.create_calendar_year_storage_path(year)
            else:
                node_storage_path = ""
            
            year_node = calendar_schemas.CalendarYearNode(
                uuid_string=calendar_year_uuid_string,
                year=str(year),
                node_storage_path=node_storage_path
            )
            neon.create_or_merge_neontology_node(year_node, database=db_name, operation='merge')
            calendar_nodes['calendar_year_nodes'].append(year_node)
            created_years[year] = year_node
            logger.info(f"Year node created: {year_node.uuid_string}")
            
            if last_year_node:
                neon.create_or_merge_neontology_relationship(
                    calendar_sequence_relationships.YearFollowsYear(source=last_year_node, target=year_node),
                    database=db_name,
                    operation='merge'
                )
                logger.info(f"Relationship created from {last_year_node.uuid_string} to {year_node.uuid_string}")
            last_year_node = year_node

        calendar_month_uuid_string = f"{year}_{month}"
        
        month_key = f"{year}-{month}"
        if month_key not in created_months:
            # Generate storage path for month node using Supabase Storage
            if storage_tools:
                month_dir_created, node_storage_path = storage_tools.create_calendar_month_storage_path(year, month)
            else:
                node_storage_path = ""

            month_node = calendar_schemas.CalendarMonthNode(
                uuid_string=calendar_month_uuid_string,
                year=str(year),
                month=str(month),
                month_name=datetime(year, month, 1).strftime('%B'),
                node_storage_path=node_storage_path
            )
            neon.create_or_merge_neontology_node(month_node, database=db_name, operation='merge')
            calendar_nodes['calendar_month_nodes'].append(month_node)
            created_months[month_key] = month_node
            logger.info(f"Month node created: {month_node.uuid_string}")

            # Check for the end of year transition for months
            if last_month_node:
                if int(month) == 1 and int(last_month_node.month) == 12 and int(last_month_node.year) == year - 1:
                    neon.create_or_merge_neontology_relationship(
                        calendar_sequence_relationships.MonthFollowsMonth(source=last_month_node, target=month_node),
                        database=db_name,
                        operation='merge'
                    )
                    logger.info(f"Relationship created from {last_month_node.uuid_string} to {month_node.uuid_string}")
                elif int(month) == int(last_month_node.month) + 1:
                    neon.create_or_merge_neontology_relationship(
                        calendar_sequence_relationships.MonthFollowsMonth(source=last_month_node, target=month_node),
                        database=db_name,
                        operation='merge'
                    )
                    logger.info(f"Relationship created from {last_month_node.uuid_string} to {month_node.uuid_string}")
            last_month_node = month_node

            neon.create_or_merge_neontology_relationship(
                calendar_relationships.YearIncludesMonth(source=year_node, target=month_node),
                database=db_name,
                operation='merge'
            )
            logger.info(f"Relationship created from {year_node.uuid_string} to {month_node.uuid_string}")
        
        calendar_week_uuid_string = f"{iso_year}_{iso_week}"
        
        week_key = f"{iso_year}-W{iso_week}"
        if week_key not in created_weeks:
            # Get the date of the first monday of the week
            week_start_date = current_date - timedelta(days=current_date.weekday())
            # Generate storage path for week node using Supabase Storage
            if storage_tools:
                week_dir_created, node_storage_path = storage_tools.create_calendar_week_storage_path(iso_year, iso_week)
            else:
                node_storage_path = ""

            week_node = calendar_schemas.CalendarWeekNode(
                uuid_string=calendar_week_uuid_string,
                start_date=week_start_date,
                week_number=str(iso_week),
                iso_week=f"{iso_year}-W{iso_week:02}",
                node_storage_path=node_storage_path
            )
            neon.create_or_merge_neontology_node(week_node, database=db_name, operation='merge')
            calendar_nodes['calendar_week_nodes'].append(week_node)
            created_weeks[week_key] = week_node
            logger.info(f"Week node created: {week_node.uuid_string}")

            if last_week_node and ((last_week_node.iso_week.split('-')[0] == str(iso_year) and int(last_week_node.week_number) == int(iso_week) - 1) or
                                (last_week_node.iso_week.split('-')[0] != str(iso_year) and int(last_week_node.week_number) == 52 and int(iso_week) == 1)):
                neon.create_or_merge_neontology_relationship(
                    calendar_sequence_relationships.WeekFollowsWeek(source=last_week_node, target=week_node),
                    database=db_name,
                    operation='merge'
                )
                logger.info(f"Relationship created from {last_week_node.uuid_string} to {week_node.uuid_string}")
            last_week_node = week_node

            neon.create_or_merge_neontology_relationship(
                calendar_relationships.YearIncludesWeek(source=year_node, target=week_node),
                database=db_name,
                operation='merge'
            )
            logger.info(f"Relationship created from {year_node.uuid_string} to {week_node.uuid_string}")
        
        # Day node management
        calendar_day_uuid_string = f"{year}_{month}_{day}"
        
        day_key = f"{year}-{month}-{day}"
        # Generate storage path for day node using Supabase Storage
        if storage_tools:
            day_dir_created, node_storage_path = storage_tools.create_calendar_day_storage_path(year, month, day)
            # Store day path for later use in time chunks
            created_days[day_key] = {'node': None, 'path': node_storage_path}
        else:
            node_storage_path = ""
            created_days[day_key] = {'node': None, 'path': None}

        day_node = calendar_schemas.CalendarDayNode(
            uuid_string=calendar_day_uuid_string,
            date=current_date,
            day_of_week=current_date.strftime('%A'),
            iso_day=f"{year}-{month:02}-{day:02}",
            node_storage_path=node_storage_path
        )
        neon.create_or_merge_neontology_node(day_node, database=db_name, operation='merge')
        calendar_nodes['calendar_day_nodes'].append(day_node)
        created_days[day_key]['node'] = day_node
        logger.info(f"Day node created: {day_node.uuid_string}")

        if last_day_node:
            neon.create_or_merge_neontology_relationship(
                calendar_sequence_relationships.DayFollowsDay(source=last_day_node, target=day_node),
                database=db_name,
                operation='merge'
            )
            logger.info(f"Relationship created from {last_day_node.uuid_string} to {day_node.uuid_string}")
        last_day_node = day_node

        neon.create_or_merge_neontology_relationship(
            calendar_relationships.MonthIncludesDay(source=month_node, target=day_node),
            database=db_name,
            operation='merge'
        )
        logger.info(f"Relationship created from {month_node.uuid_string} to {day_node.uuid_string}")
        neon.create_or_merge_neontology_relationship(
            calendar_relationships.WeekIncludesDay(source=week_node, target=day_node),
            database=db_name,
            operation='merge'
        )
        logger.info(f"Relationship created from {week_node.uuid_string} to {day_node.uuid_string}")
        current_date += timedelta(days=1)
    
    if time_chunk_node_length:
        time_chunk_interval = time_chunk_node_length
        # Get every calendar day node and create time chunks of length time_chunk_node minutes for the whole day
        for day_node in calendar_nodes['calendar_day_nodes']:
            total_time_chunks_in_day = (24 * 60) / time_chunk_interval
            for i in range(total_time_chunks_in_day):
                time_chunk_uuid_string = f"{day_node.uuid_string}_{i}"
                time_chunk_start_time = day_node.date.time() + timedelta(minutes=i * time_chunk_interval)
                time_chunk_end_time = time_chunk_start_time + timedelta(minutes=time_chunk_interval)
                # Generate storage path for time chunk node using Supabase Storage
                if storage_tools:
                    chunk_id = f"{day_node.uuid_string}_{i:02d}"
                    chunk_dir_created, node_storage_path = storage_tools.create_calendar_time_chunk_storage_path(day_node.uuid_string, i)
                else:
                    node_storage_path = ""

                time_chunk_node = calendar_schemas.CalendarTimeChunkNode(
                    uuid_string=time_chunk_uuid_string,
                    start_time=time_chunk_start_time,
                    end_time=time_chunk_end_time,
                    node_storage_path=node_storage_path
                )
                neon.create_or_merge_neontology_node(time_chunk_node, database=db_name, operation='merge')
                calendar_nodes['calendar_time_chunk_nodes'].append(time_chunk_node)
                logger.info(f"Time chunk node created: {time_chunk_node.uuid_string}")
                # Create a relationship between the time chunk node and the day node
                neon.create_or_merge_neontology_relationship(
                    calendar_relationships.DayIncludesTimeChunk(source=day_node, target=time_chunk_node),
                    database=db_name,
                    operation='merge'
                )
                logger.info(f"Relationship created from {day_node.uuid_string} to {time_chunk_node.uuid_string}")
                # Create sequential relationship between the time chunk nodes
                if i > 0:
                    neon.create_or_merge_neontology_relationship(
                        calendar_sequence_relationships.TimeChunkFollowsTimeChunk(source=calendar_nodes['calendar_time_chunk_nodes'][i-1], target=time_chunk_node),
                        database=db_name,
                        operation='merge'
                    )
                    logger.info(f"Relationship created from {calendar_nodes['calendar_time_chunk_nodes'][i-1].uuid_string} to {time_chunk_node.uuid_string}")
        
    logger.info(f'Calendar structure created successfully for {start_date} to {end_date}')
    return calendar_nodes