from datetime import datetime
from uuid import UUID

from reflector.dailyco_api import (
    CreateMeetingTokenRequest,
    CreateRoomRequest,
    DailyApiClient,
    MeetingParticipantsResponse,
    MeetingTokenProperties,
    RecordingResponse,
    RecordingsBucketConfig,
    RoomPresenceResponse,
    RoomProperties,
    verify_webhook_signature,
)
from reflector.dailyco_api import RecordingType as DailyRecordingType
from reflector.db.daily_participant_sessions import (
    daily_participant_sessions_controller,
)
from reflector.db.meetings import meetings_controller
from reflector.db.rooms import Room
from reflector.logger import logger
from reflector.storage import get_dailyco_storage

from ..dailyco_api.responses import RecordingStatus
from ..schemas.platform import Platform
from ..utils.daily import DailyRoomName
from ..utils.string import NonEmptyString
from .base import ROOM_PREFIX_SEPARATOR, VideoPlatformClient
from .models import MeetingData, RecordingType, SessionData, VideoPlatformConfig


class DailyClient(VideoPlatformClient):
    PLATFORM_NAME: Platform = "daily"
    TIMESTAMP_FORMAT = "%Y%m%d%H%M%S"
    RECORDING_NONE: RecordingType = "none"
    RECORDING_LOCAL: RecordingType = "local"
    RECORDING_CLOUD: RecordingType = "cloud"

    def __init__(self, config: VideoPlatformConfig):
        super().__init__(config)
        self._api_client = DailyApiClient(
            api_key=config.api_key,
            webhook_secret=config.webhook_secret,
            timeout=10.0,
        )

    async def create_meeting(
        self, room_name_prefix: NonEmptyString, end_date: datetime, room: Room
    ) -> MeetingData:
        """
        Daily.co rooms vs meetings:
        - We create a NEW Daily.co room for each Reflector meeting
        - Daily.co meeting/session starts automatically when first participant joins
        - Room auto-deletes after exp time
        - Meeting.room_name stores the timestamped Daily.co room name
        """
        timestamp = datetime.now().strftime(self.TIMESTAMP_FORMAT)
        room_name = f"{room_name_prefix}{ROOM_PREFIX_SEPARATOR}{timestamp}"

        enable_recording = None
        if room.recording_type == self.RECORDING_LOCAL:
            enable_recording = "local"
        elif room.recording_type == self.RECORDING_CLOUD:
            # Don't set enable_recording - recordings started via REST API (not auto-start)
            enable_recording = None

        properties = RoomProperties(
            enable_recording=enable_recording,
            enable_chat=True,
            enable_screenshare=True,
            enable_knocking=room.is_locked,
            start_video_off=False,
            start_audio_off=False,
            exp=int(end_date.timestamp()),
        )

        if room.recording_type == self.RECORDING_CLOUD:
            daily_storage = get_dailyco_storage()
            assert daily_storage.bucket_name, "S3 bucket must be configured"
            properties.recordings_bucket = RecordingsBucketConfig(
                bucket_name=daily_storage.bucket_name,
                bucket_region=daily_storage.region,
                assume_role_arn=daily_storage.role_credential,
                allow_api_access=True,
            )

        request = CreateRoomRequest(
            name=room_name,
            privacy="private" if room.is_locked else "public",
            properties=properties,
        )

        result = await self._api_client.create_room(request)

        return MeetingData(
            meeting_id=result.id,
            room_name=result.name,
            room_url=result.url,
            host_room_url=result.url,
            platform=self.PLATFORM_NAME,
            extra_data=result.model_dump(),
        )

    async def get_room_sessions(self, room_name: str) -> list[SessionData]:
        """Get room session history from database (webhook-stored sessions).

        Daily.co doesn't provide historical session API, so we query our database
        where participant.joined/left webhooks are stored.
        """
        meeting = await meetings_controller.get_by_room_name(room_name)
        if not meeting:
            return []

        sessions = await daily_participant_sessions_controller.get_by_meeting(
            meeting.id
        )

        return [
            SessionData(
                session_id=s.id,
                started_at=s.joined_at,
                ended_at=s.left_at,
            )
            for s in sessions
        ]

    async def get_room_presence(self, room_name: str) -> RoomPresenceResponse:
        """Get room presence/session data for a Daily.co room."""
        return await self._api_client.get_room_presence(room_name)

    async def get_meeting_participants(
        self, meeting_id: str
    ) -> MeetingParticipantsResponse:
        """Get participant data for a specific Daily.co meeting."""
        return await self._api_client.get_meeting_participants(meeting_id)

    async def get_recording(self, recording_id: str) -> RecordingResponse:
        return await self._api_client.get_recording(recording_id)

    async def list_recordings(
        self,
        room_name: NonEmptyString | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        limit: int = 100,
    ) -> list[RecordingResponse]:
        return await self._api_client.list_recordings(
            room_name=room_name,
            starting_after=starting_after,
            ending_before=ending_before,
            limit=limit,
        )

    async def get_recording_status(
        self, recording_id: NonEmptyString
    ) -> RecordingStatus:
        recording = await self.get_recording(recording_id)
        return recording.status

    async def upload_logo(self, room_name: str, logo_path: str) -> bool:
        return True

    def verify_webhook_signature(
        self, body: bytes, signature: str, timestamp: str | None = None
    ) -> bool:
        """Verify Daily.co webhook signature using dailyco_api module."""
        if not self.config.webhook_secret:
            logger.warning("Webhook secret not configured")
            return False

        return verify_webhook_signature(
            body=body,
            signature=signature,
            timestamp=timestamp or "",
            webhook_secret=self.config.webhook_secret,
        )

    async def create_meeting_token(
        self,
        room_name: DailyRoomName,
        enable_recording_ui: bool,
        user_id: NonEmptyString | None = None,
        is_owner: bool = False,
        max_recording_duration_seconds: int | None = None,
    ) -> NonEmptyString:
        properties = MeetingTokenProperties(
            room_name=room_name,
            user_id=user_id,
            enable_recording_ui=enable_recording_ui,
            is_owner=is_owner,
        )
        request = CreateMeetingTokenRequest(properties=properties)
        result = await self._api_client.create_meeting_token(request)
        return result.token

    async def start_recording(
        self,
        room_name: DailyRoomName,
        recording_type: DailyRecordingType,
        instance_id: UUID,
    ) -> dict:
        """Start recording via Daily.co REST API.

        Args:
            instance_id: UUID for this recording session - one UUID per "room" in Daily (which is "meeting" in Reflector)
        """
        return await self._api_client.start_recording(
            room_name=room_name,
            recording_type=recording_type,
            instance_id=instance_id,
        )

    async def close(self):
        """Clean up API client resources."""
        await self._api_client.close()

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.close()
