from datetime import datetime, timedelta, timezone

import structlog
from celery import shared_task
from celery.utils.log import get_task_logger

from reflector.asynctask import asynctask
from reflector.db.calendar_events import calendar_events_controller
from reflector.db.meetings import meetings_controller
from reflector.db.rooms import Room, rooms_controller
from reflector.redis_cache import RedisAsyncLock
from reflector.services.ics_sync import SyncStatus, ics_sync_service
from reflector.video_platforms.factory import create_platform_client

logger = structlog.wrap_logger(get_task_logger(__name__))


@shared_task
@asynctask
async def sync_room_ics(room_id: str):
    try:
        room = await rooms_controller.get_by_id(room_id)
        if not room:
            logger.warning("Room not found for ICS sync", room_id=room_id)
            return

        if not room.ics_enabled or not room.ics_url:
            logger.debug("ICS not enabled for room", room_id=room_id)
            return

        logger.info("Starting ICS sync for room", room_id=room_id, room_name=room.name)
        result = await ics_sync_service.sync_room_calendar(room)

        if result["status"] == SyncStatus.SUCCESS:
            logger.info(
                "ICS sync completed successfully",
                room_id=room_id,
                events_found=result.get("events_found", 0),
                events_created=result.get("events_created", 0),
                events_updated=result.get("events_updated", 0),
                events_deleted=result.get("events_deleted", 0),
            )
        elif result["status"] == SyncStatus.UNCHANGED:
            logger.debug("ICS content unchanged", room_id=room_id)
        elif result["status"] == SyncStatus.ERROR:
            logger.error("ICS sync failed", room_id=room_id, error=result.get("error"))
        else:
            logger.debug(
                "ICS sync skipped", room_id=room_id, reason=result.get("reason")
            )

    except Exception as e:
        logger.error("Unexpected error during ICS sync", room_id=room_id, error=str(e))


@shared_task
@asynctask
async def sync_all_ics_calendars():
    try:
        logger.info("Starting sync for all ICS-enabled rooms")

        ics_enabled_rooms = await rooms_controller.get_ics_enabled()
        logger.info(f"Found {len(ics_enabled_rooms)} rooms with ICS enabled")

        for room in ics_enabled_rooms:
            if not _should_sync(room):
                logger.debug("Skipping room, not time to sync yet", room_id=room.id)
                continue

            sync_room_ics.delay(room.id)

        logger.info("Queued sync tasks for all eligible rooms")

    except Exception as e:
        logger.error("Error in sync_all_ics_calendars", error=str(e))


def _should_sync(room) -> bool:
    if not room.ics_last_sync:
        return True

    time_since_sync = datetime.now(timezone.utc) - room.ics_last_sync
    return time_since_sync.total_seconds() >= room.ics_fetch_interval


async def create_upcoming_meetings_for_event(event, create_window, room: Room):
    if event.start_time <= create_window:
        return
    existing_meeting = await meetings_controller.get_by_calendar_event(event.id, room)

    if existing_meeting:
        return

    logger.info(
        "Pre-creating meeting for calendar event",
        room_id=room.id,
        event_id=event.id,
        event_title=event.title,
    )

    try:
        # 8h rejoin window matches manual on-the-fly meetings; the scheduled
        # DTEND stays in calendar_events.end_time for reference.
        end_date = event.start_time + timedelta(hours=8)

        client = create_platform_client(room.platform)

        meeting_data = await client.create_meeting(
            room.name,
            end_date=end_date,
            room=room,
        )
        await client.upload_logo(meeting_data.room_name, "./images/logo.png")

        meeting = await meetings_controller.create(
            id=meeting_data.meeting_id,
            room_name=meeting_data.room_name,
            room_url=meeting_data.room_url,
            host_room_url=meeting_data.host_room_url,
            start_date=event.start_time,
            end_date=end_date,
            room=room,
            calendar_event_id=event.id,
            calendar_metadata={
                "title": event.title,
                "description": event.description,
                "attendees": event.attendees,
            },
        )

        logger.info(
            "Meeting pre-created successfully",
            meeting_id=meeting.id,
            event_id=event.id,
        )

    except Exception as e:
        logger.error(
            "Failed to pre-create meeting",
            room_id=room.id,
            event_id=event.id,
            error=str(e),
        )


@shared_task
@asynctask
async def create_upcoming_meetings():
    async with RedisAsyncLock("create_upcoming_meetings", skip_if_locked=True) as lock:
        if not lock.acquired:
            logger.warning(
                "Another worker is already creating upcoming meetings, skipping"
            )
            return

        try:
            logger.info("Starting creation of upcoming meetings")

            ics_enabled_rooms = await rooms_controller.get_ics_enabled()
            now = datetime.now(timezone.utc)
            create_window = now - timedelta(minutes=6)

            for room in ics_enabled_rooms:
                events = await calendar_events_controller.get_upcoming(
                    room.id,
                    minutes_ahead=7,
                )

                for event in events:
                    await create_upcoming_meetings_for_event(event, create_window, room)
            logger.info("Completed pre-creation check for upcoming meetings")

        except Exception as e:
            logger.error("Error in create_upcoming_meetings", error=str(e))
