"""Data models for the Meemo Python client.

This module contains Pydantic models for request and response data structures
used in the Meemo Python client library.

Example:
    >>> from meemo.models import MeetingListParams
    >>> params = MeetingListParams(title="standup", summary_complete=True)
    >>> filters = params.to_query_params()

Authors:
    GDP Labs

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

from enum import StrEnum
from typing import Any

from pydantic import BaseModel

# =============================================================================
# Common Enums
# =============================================================================


class MeetingStatus(StrEnum):
    """Status of a meeting."""

    UPCOMING = "upcoming"
    ONGOING = "ongoing"
    RECORDING = "recording"
    PAST = "past"


class RecordingFormat(StrEnum):
    """Supported recording audio formats."""

    MP3 = "mp3"
    WAV = "wav"


# =============================================================================
# Authentication Models
# =============================================================================


class TokenResponse(BaseModel):
    """Response from the OAuth2 token endpoint.

    Attributes:
        access_token: The JWT access token for API authentication.
        token_type: Token type, typically "Bearer".
        expires_in: Token lifetime in seconds (default: 10800 = 3 hours).
        scope: Token scope, typically "read write".
    """

    access_token: str
    token_type: str
    expires_in: int
    scope: str


# =============================================================================
# Calendar Event Models
# =============================================================================


class CalendarAttendee(BaseModel):
    """Attendee information from a calendar event.

    Attributes:
        email: Attendee email address.
        display_name: Attendee display name (may be None).
        response_status: RSVP status (accepted/declined/tentative/needsAction).
    """

    email: str
    display_name: str | None = None
    response_status: str


class CalendarEvent(BaseModel):
    """Calendar event data for meetings created from calendar integration.

    Attributes:
        event_id: Google Calendar event ID.
        summary: Event summary/title from calendar.
        organizer_email: Email of the meeting organizer.
        attendees: List of attendees from the calendar invite.
        meeting_link: Video conference link (e.g., Google Meet URL).
        start_time: Event start time from calendar (ISO 8601).
        end_time: Event end time from calendar (ISO 8601).
    """

    event_id: str
    summary: str
    organizer_email: str | None = None
    attendees: list[CalendarAttendee] = []
    meeting_link: str | None = None
    start_time: str
    end_time: str


# =============================================================================
# Meeting List Models
# =============================================================================


class MeetingListItem(BaseModel):
    """Meeting item returned in the list meetings response.

    Attributes:
        id: Meeting ID.
        title: Meeting title.
        start_time: Meeting start time (ISO 8601).
        end_time: Meeting end time (ISO 8601).
        created_at: Meeting creation time (ISO 8601).
        status: Meeting status (upcoming, ongoing, recording, past).
        summary_complete: Whether summary generation is complete.
        host_name: Full name of the meeting host.
        calendar_event: Calendar event data if from calendar integration.
    """

    id: int
    title: str
    start_time: str
    end_time: str
    created_at: str
    status: str
    summary_complete: bool
    host_name: str
    calendar_event: CalendarEvent | None = None


class MeetingListResponse(BaseModel):
    """Paginated response from the list meetings endpoint.

    Attributes:
        count: Total number of meetings across all pages.
        next: URL to the next page of results (None if last page).
        previous: URL to the previous page of results (None if first page).
        results: List of meeting objects for the current page.
    """

    count: int
    next: str | None = None
    previous: str | None = None
    results: list[MeetingListItem]


# =============================================================================
# Meeting Detail Models
# =============================================================================


class MeetingHost(BaseModel):
    """Host user information for a meeting.

    Attributes:
        id: User ID.
        name: Host full name.
        email: Host email address.
    """

    id: int
    name: str
    email: str


class MeetingDetail(BaseModel):
    """Detailed information about a specific meeting.

    Attributes:
        id: Meeting ID.
        title: Meeting title.
        start_time: Meeting start time (ISO 8601).
        end_time: Meeting end time (ISO 8601).
        created_at: Meeting creation time (ISO 8601).
        location: Meeting location.
        status: Meeting status (upcoming, ongoing, recording, past).
        summary_complete: Whether summary generation is complete.
        host: Host user information (id, name, email).
        language: Meeting language code (e.g., "id", "en").
        keywords: List of keyword tags.
        participant_count: Number of participants.
        duration_seconds: Meeting duration in seconds.
        num_cluster: Number of speaker clusters detected during diarization.
        calendar_event: Calendar event data if from calendar integration.
    """

    id: int
    title: str
    start_time: str
    end_time: str
    created_at: str
    location: str = ""
    status: str
    summary_complete: bool
    host: MeetingHost
    language: str = ""
    keywords: list[str] = []
    participant_count: int = 0
    duration_seconds: float = 0.0
    num_cluster: int = 0
    calendar_event: CalendarEvent | None = None


# =============================================================================
# Transcript Models
# =============================================================================


class TranscriptSegment(BaseModel):
    """A single transcript segment from a meeting.

    Attributes:
        speaker: Speaker name or "Unknown" if unidentified.
        text: Transcript text (revised > formatted > raw).
        start_time: Segment start time in seconds.
        end_time: Segment end time in seconds.
    """

    speaker: str
    text: str
    start_time: float
    end_time: float


class TranscriptResponse(BaseModel):
    """Response from the meeting transcript endpoint.

    Attributes:
        meeting_id: Meeting ID.
        title: Meeting title.
        total_segments: Total number of transcript segments.
        transcripts: Array of transcript segments.
    """

    meeting_id: int
    title: str
    total_segments: int
    transcripts: list[TranscriptSegment]


# =============================================================================
# Summary Models
# =============================================================================


class SummaryResponse(BaseModel):
    """Response from the meeting summary endpoint.

    Note:
        The ``summary`` field may be a Markdown-formatted string (new format)
        or a structured JSON object (legacy format). Integrations should handle
        both during the transition period.

    Attributes:
        meeting_id: Meeting ID.
        title: Meeting title.
        summary: Meeting summary content (Markdown string or legacy JSON object).
        notes: Meeting notes text.
        keywords: List of keyword tags.
    """

    meeting_id: int
    title: str
    summary: str | dict[str, Any] | None = None
    notes: str = ""
    keywords: list[str] = []


# =============================================================================
# Participants Models
# =============================================================================


class Participant(BaseModel):
    """A meeting participant.

    Attributes:
        id: User ID (None for external guests).
        name: Participant display name.
        email: Participant email address.
        position: Position within organization.
        department: Department within organization.
    """

    id: int | None = None
    name: str
    email: str | None = None
    position: str = ""
    department: str = ""


class ParticipantsResponse(BaseModel):
    """Response from the meeting participants endpoint.

    Attributes:
        meeting_id: Meeting ID.
        title: Meeting title.
        total_participants: Total number of participants.
        participants: Array of participant objects.
    """

    meeting_id: int
    title: str
    total_participants: int
    participants: list[Participant]


# =============================================================================
# Recording Models
# =============================================================================


class RecordingResponse(BaseModel):
    """Response from the meeting recording endpoint.

    Attributes:
        meeting_id: Meeting ID.
        title: Meeting title.
        recording_url: Relative URL to recording file (None if no recording).
        duration: Recording duration in seconds.
        format: Audio format ("mp3", "wav", or empty string).
    """

    meeting_id: int
    title: str
    recording_url: str | None = None
    duration: float = 0.0
    format: str = ""


# =============================================================================
# Query Parameter Models
# =============================================================================


class MeetingListParams(BaseModel):
    """Query parameters for the list meetings endpoint.

    Attributes:
        organization_id: Filter to a specific organization.
        title: Filter by title (case-insensitive, contains match).
        participants: Filter by participant user IDs (comma-separated).
        created_after: Filter meetings created on or after this date (YYYY-MM-DD).
        created_before: Filter meetings created on or before this date (YYYY-MM-DD).
        summary_complete: Filter by summary completion status.
        from_calendar: Filter by meeting source (True=calendar, False=manual).
        page: Page number for pagination.
        size: Number of results per page (default: 10).
    """

    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

    def to_query_params(self) -> dict[str, str | int | bool]:
        """Convert to a dictionary of non-None query parameters.

        Returns:
            dict[str, str | int | bool]: Dictionary of query parameter key-value pairs.
        """
        params: dict[str, str | int | bool] = {}
        for field_name, value in self.model_dump().items():
            if value is not None:
                params[field_name] = value
        return params


# =============================================================================
# Webhook Models
# =============================================================================


class AvailableOrganization(BaseModel):
    """Organization accessible to the external application for webhooks.

    Attributes:
        id: Organization ID.
        name: Organization name.
    """

    id: int
    name: str


class CreateWebhookBody(BaseModel):
    """Request body for creating a webhook.

    Attributes:
        target_url: HTTPS URL where events will be sent.
        events: List of event types to subscribe to.
        organization_ids: List of organization IDs to monitor.
        description: Optional description of the webhook.
    """

    target_url: str
    events: list[str]
    organization_ids: list[int]
    description: str | None = None


class Webhook(BaseModel):
    """Webhook registration.

    Attributes:
        id: Webhook ID.
        target_url: URL where events are sent.
        secret_key: Secret for signing payloads (e.g. whsec_...).
        events: List of subscribed event types.
        is_active: Whether the webhook is active.
        description: Optional description.
        created_at: Creation time (ISO 8601).
        organization_id: Organization this webhook belongs to.
        failure_count: Number of delivery failures (detail view).
        last_failure_reason: Last failure reason (detail view).
    """

    id: int
    target_url: str
    secret_key: str
    events: list[str]
    is_active: bool
    description: str = ""
    created_at: str
    organization_id: int
    failure_count: int = 0
    last_failure_reason: str = ""


class WebhookListResponse(BaseModel):
    """Paginated list of webhooks.

    Attributes:
        count: Total number of webhooks.
        next: URL to next page (None if last page).
        previous: URL to previous page (None if first page).
        results: List of webhook objects.
    """

    count: int
    next: str | None = None
    previous: str | None = None
    results: list[Webhook]


class WebhookEvent(BaseModel):
    """Webhook delivery log entry.

    Attributes:
        id: Event log ID.
        webhook_id: Webhook that was triggered.
        event_uuid: Unique event identifier.
        event_type: Event type (e.g. meeting.created).
        status: Delivery status (e.g. SUCCESS).
        response_status: HTTP status from target URL.
        attempt_count: Number of delivery attempts.
        created_at: When the event was processed (ISO 8601).
    """

    id: int
    webhook_id: int
    event_uuid: str
    event_type: str
    status: str
    response_status: int
    attempt_count: int
    created_at: str


class WebhookEventListResponse(BaseModel):
    """Paginated list of webhook event logs.

    Attributes:
        count: Total number of events.
        results: List of webhook event objects.
    """

    count: int
    results: list[WebhookEvent]


# =============================================================================
# Create Meeting Models
# =============================================================================


class CreateMeetingCalendarEvent(BaseModel):
    """Calendar event data for create meeting requests.

    Unlike ``CalendarEvent``, only ``event_id`` is required.  The remaining
    fields are optional so callers can provide as much or as little
    calendar context as available.

    Attributes:
        event_id: Google Calendar event ID.
        summary: Event summary/title from calendar.
        organizer_email: Email of the meeting organizer.
        attendees: List of attendees from the calendar invite.
        meeting_link: Video conference link (e.g., Google Meet URL).
        start_time: Event start time from calendar (ISO 8601).
        end_time: Event end time from calendar (ISO 8601).
    """

    event_id: str
    summary: str | None = None
    organizer_email: str | None = None
    attendees: list[CalendarAttendee] = []
    meeting_link: str | None = None
    start_time: str | None = None
    end_time: str | None = None


class CreateMeetingBody(BaseModel):
    """Request body for creating a meeting.

    Attributes:
        organization_id: Organization that owns the meeting.
        title: Meeting title.
        start_time: Meeting start time (ISO 8601).
        user_token: Token of the user creating the meeting.
        topic_id: Topic to associate with the meeting.
        participants: Comma-separated participant user IDs.
        bot_meeting_url: URL for a bot to join (mutually exclusive
            with ``file_url``).
        bot_join_at: Schedule the bot to join at a future time (ISO 8601).
            If omitted or ``None``, the bot joins immediately when
            ``bot_meeting_url`` is provided.
        file_url: URL of a pre-recorded file (mutually exclusive
            with ``bot_meeting_url``).
        speaker_count: Expected number of speakers (>= 1).
        calendar_event: Optional calendar event context.
    """

    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


# =============================================================================
# Topic Models
# =============================================================================


class Topic(BaseModel):
    """A meeting topic.

    Attributes:
        id: Topic ID.
        name: Topic display name.
        alias: Short alias for the topic.
        language: Language code (e.g., "id", "en").
    """

    id: int
    name: str
    alias: str = ""
    language: str = ""


# =============================================================================
# Usage Models
# =============================================================================


class UsageItem(BaseModel):
    """A single usage record for an organization capability.

    Attributes:
        organization_id: Organization ID.
        organization_name: Organization display name.
        capability_name: Name of the capability being measured.
        usage: Current usage amount.
        quota: Allowed quota, or None if not applicable.
    """

    organization_id: int
    organization_name: str
    capability_name: str
    usage: float
    quota: int | None


class UsageResponse(BaseModel):
    """Response from the usage endpoint.

    Attributes:
        results: List of usage records.
    """

    results: list[UsageItem]
