"""Meetings handling for the Meemo Python client.

This module provides the Meetings class for accessing meeting data
from the Meemo External API, including meeting details, transcripts,
summaries, participants, and recordings.

Authors:
    GDP Labs

References:
    https://gdplabs.gitbook.io/meemo/resources/external-api-documentation
"""

import logging

from meemo._base import _ERR_EXPECTED_DICT, _ERR_EXPECTED_LIST, _BaseMeetingsMixin, _BaseService
from meemo.models import (
    CreateMeetingCalendarEvent,
    MeetingDetail,
    MeetingListResponse,
    ParticipantsResponse,
    RecordingResponse,
    SummaryResponse,
    Topic,
    TranscriptResponse,
)

logger = logging.getLogger(__name__)


class Meetings(_BaseService, _BaseMeetingsMixin):
    """Handles Meeting API operations for the Meemo External API."""

    def list_meetings(
        self,
        organization_id: int | None = None,
        title: str | None = None,
        participants: str | None = None,
        created_after: str | None = None,
        created_before: str | None = None,
        summary_complete: bool | None = None,
        from_calendar: bool | None = None,
        page: int | None = None,
        size: int | None = None,
        extra_headers: dict[str, str] | None = None,
    ) -> MeetingListResponse:
        """List meetings for your accessible organization(s).

        Returns a paginated list of meetings ordered by start time descending
        (newest first).

        Args:
            organization_id (int | None): Filter to a specific organization.
                If not provided, returns meetings from all accessible organizations.
            title (str | None): Filter by title (case-insensitive, contains match).
            participants (str | None): Filter by participant user IDs (comma-separated).
            created_after (str | None): Filter meetings created on or after this date
                (YYYY-MM-DD).
            created_before (str | None): Filter meetings created on or before this date
                (YYYY-MM-DD).
            summary_complete (bool | None): Filter by summary completion status.
            from_calendar (bool | None): Filter by meeting source.
                True=calendar integration, False=manually created.
            page (int | None): Page number for pagination.
            size (int | None): Number of results per page (default: 10).
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            MeetingListResponse: Paginated list of meetings.

        Raises:
            httpx.HTTPStatusError: If the API request fails.
        """
        logger.debug("Listing meetings")

        url = self._meeting_url()
        headers = self._prepare_headers(extra_headers)
        params = self._build_list_params(
            organization_id=organization_id,
            title=title,
            participants=participants,
            created_after=created_after,
            created_before=created_before,
            summary_complete=summary_complete,
            from_calendar=from_calendar,
            page=page,
            size=size,
        )

        response_data = self._make_request("GET", url, headers, params=params)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return MeetingListResponse(**response_data)

    def get_meeting(
        self,
        meeting_id: int,
        extra_headers: dict[str, str] | None = None,
    ) -> MeetingDetail:
        """Get detailed information about a specific meeting.

        The meeting must belong to one of your accessible organizations.

        Args:
            meeting_id (int): Meeting ID.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            MeetingDetail: Detailed meeting information.

        Raises:
            ValueError: If meeting_id is not a positive integer.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_meeting_id(meeting_id)
        logger.debug("Retrieving meeting: %d", meeting_id)

        url = self._meeting_url(f"{meeting_id}/")
        headers = self._prepare_headers(extra_headers)

        response_data = self._make_request("GET", url, headers)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return MeetingDetail(**response_data)

    def get_transcript(
        self,
        meeting_id: int,
        extra_headers: dict[str, str] | None = None,
    ) -> TranscriptResponse:
        """Get the transcript of a specific meeting.

        Returns the meeting transcript as a JSON array of segments, ordered by
        start time. Confidential segments are excluded.

        Args:
            meeting_id (int): Meeting ID.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            TranscriptResponse: Meeting transcript with segments.

        Raises:
            ValueError: If meeting_id is not a positive integer.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_meeting_id(meeting_id)
        logger.debug("Retrieving transcript for meeting: %d", meeting_id)

        url = self._meeting_url(f"{meeting_id}/transcript/")
        headers = self._prepare_headers(extra_headers)

        response_data = self._make_request("GET", url, headers)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return TranscriptResponse(**response_data)

    def get_summary(
        self,
        meeting_id: int,
        extra_headers: dict[str, str] | None = None,
    ) -> SummaryResponse:
        """Get the summary of a specific meeting.

        Returns the meeting summary, notes, and keywords. The summary field
        may be a Markdown string (new format) or a structured JSON object
        (legacy format).

        Args:
            meeting_id (int): Meeting ID.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            SummaryResponse: Meeting summary with notes and keywords.

        Raises:
            ValueError: If meeting_id is not a positive integer.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_meeting_id(meeting_id)
        logger.debug("Retrieving summary for meeting: %d", meeting_id)

        url = self._meeting_url(f"{meeting_id}/summary/")
        headers = self._prepare_headers(extra_headers)

        response_data = self._make_request("GET", url, headers)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return SummaryResponse(**response_data)

    def get_participants(
        self,
        meeting_id: int,
        extra_headers: dict[str, str] | None = None,
    ) -> ParticipantsResponse:
        """Get the list of participants for a specific meeting.

        Args:
            meeting_id (int): Meeting ID.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            ParticipantsResponse: Meeting participants list.

        Raises:
            ValueError: If meeting_id is not a positive integer.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_meeting_id(meeting_id)
        logger.debug("Retrieving participants for meeting: %d", meeting_id)

        url = self._meeting_url(f"{meeting_id}/participants/")
        headers = self._prepare_headers(extra_headers)

        response_data = self._make_request("GET", url, headers)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return ParticipantsResponse(**response_data)

    def get_recording(
        self,
        meeting_id: int,
        extra_headers: dict[str, str] | None = None,
    ) -> RecordingResponse:
        """Get the recording URL for a specific meeting.

        Args:
            meeting_id (int): Meeting ID.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            RecordingResponse: Meeting recording URL and metadata.

        Raises:
            ValueError: If meeting_id is not a positive integer.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_meeting_id(meeting_id)
        logger.debug("Retrieving recording for meeting: %d", meeting_id)

        url = self._meeting_url(f"{meeting_id}/recording/")
        headers = self._prepare_headers(extra_headers)

        response_data = self._make_request("GET", url, headers)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return RecordingResponse(**response_data)

    def create_meeting(
        self,
        organization_id: int,
        title: str | None = None,
        start_time: str | None = None,
        user_token: str | None = None,
        topic_id: int | None = None,
        participants: str | None = None,
        bot_meeting_url: str | None = None,
        bot_join_at: str | None = None,
        file_url: str | None = None,
        speaker_count: int | None = None,
        calendar_event: CreateMeetingCalendarEvent | None = None,
        extra_headers: dict[str, str] | None = None,
    ) -> MeetingDetail:
        """Create a new meeting.

        Args:
            organization_id (int): Organization that owns the meeting.
            title (str | None): Meeting title.
            start_time (str | None): Meeting start time (ISO 8601).
            user_token (str | None): Token of the user creating the meeting.
            topic_id (int | None): Topic to associate with the meeting.
            participants (str | None): Comma-separated participant user IDs.
            bot_meeting_url (str | None): URL for a bot to join
                (mutually exclusive with ``file_url``).
            bot_join_at (str | None): Schedule the bot to join at a future
                time (ISO 8601). If omitted, the bot joins immediately.
            file_url (str | None): URL of a pre-recorded file
                (mutually exclusive with ``bot_meeting_url``).
            speaker_count (int | None): Expected number of speakers (>= 1).
            calendar_event (CreateMeetingCalendarEvent | None): Calendar event
                context.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            MeetingDetail: The newly created meeting.

        Raises:
            ValueError: If validation fails.
            httpx.HTTPStatusError: If the API request fails.
        """
        self._validate_create_meeting_params(
            organization_id=organization_id,
            speaker_count=speaker_count,
            bot_meeting_url=bot_meeting_url,
            bot_join_at=bot_join_at,
            file_url=file_url,
        )
        logger.debug("Creating meeting for organization: %d", organization_id)

        url = self._meeting_url()
        headers = self._prepare_headers(extra_headers)
        headers["Content-Type"] = "application/json"

        json_data = self._build_create_body(
            organization_id=organization_id,
            title=title,
            start_time=start_time,
            user_token=user_token,
            topic_id=topic_id,
            participants=participants,
            bot_meeting_url=bot_meeting_url,
            bot_join_at=bot_join_at,
            file_url=file_url,
            speaker_count=speaker_count,
            calendar_event=calendar_event,
        )

        response_data = self._make_request("POST", url, headers, json_data=json_data)
        if not isinstance(response_data, dict):
            raise TypeError(_ERR_EXPECTED_DICT)
        return MeetingDetail(**response_data)

    def list_topics(
        self,
        organization_id: int | None = None,
        extra_headers: dict[str, str] | None = None,
    ) -> list[Topic]:
        """List available topics.

        Args:
            organization_id (int | None): Filter by organization.
            extra_headers (dict[str, str] | None): Additional headers.

        Returns:
            list[Topic]: List of available topics.

        Raises:
            httpx.HTTPStatusError: If the API request fails.
        """
        logger.debug("Listing topics")

        url = self._topics_url()
        headers = self._prepare_headers(extra_headers)
        params = {"organization_id": organization_id} if organization_id is not None else None

        response_data = self._make_request("GET", url, headers, params=params)
        if not isinstance(response_data, list):
            raise TypeError(_ERR_EXPECTED_LIST)
        return [Topic(**item) for item in response_data]
