"""Meeting aggregate root entity."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import TYPE_CHECKING
from uuid import UUID, uuid4

from noteflow.domain.utils.time import utc_now
from noteflow.domain.value_objects import MeetingId, MeetingState

if TYPE_CHECKING:
    from noteflow.domain.entities.segment import Segment
    from noteflow.domain.entities.summary import Summary


@dataclass(frozen=True, slots=True)
class MeetingLoadParams:
    """Parameters for loading a meeting from persistence.

    Groups optional meeting attributes to reduce parameter count.
    """

    state: MeetingState = MeetingState.CREATED
    """Meeting state."""

    created_at: datetime | None = None
    """Creation timestamp (defaults to now)."""

    started_at: datetime | None = None
    """Start timestamp."""

    ended_at: datetime | None = None
    """End timestamp."""

    metadata: dict[str, str] | None = None
    """Meeting metadata."""

    wrapped_dek: bytes | None = None
    """Encrypted data encryption key."""

    asset_path: str | None = None
    """Relative path for audio assets."""

    project_id: UUID | None = None
    """Associated project ID."""

    version: int = 1
    """Optimistic locking version."""


@dataclass
class Meeting:
    """Meeting aggregate root.

    The central entity representing a recorded meeting with its
    transcript segments and optional summary.
    """

    id: MeetingId
    title: str
    project_id: UUID | None = None
    state: MeetingState = MeetingState.CREATED
    created_at: datetime = field(default_factory=utc_now)
    started_at: datetime | None = None
    ended_at: datetime | None = None
    segments: list[Segment] = field(default_factory=list)
    summary: Summary | None = None
    metadata: dict[str, str] = field(default_factory=dict)
    wrapped_dek: bytes | None = None  # Encrypted data encryption key
    asset_path: str | None = None  # Relative path for audio assets
    version: int = 1

    @classmethod
    def create(
        cls,
        title: str = "",
        metadata: dict[str, str] | None = None,
        project_id: UUID | None = None,
    ) -> Meeting:
        """Factory method to create a new meeting.

        Args:
            title: Optional meeting title.
            metadata: Optional metadata dictionary.

        Returns:
            New Meeting instance.
        """
        meeting_id = MeetingId(uuid4())
        now = utc_now()

        from noteflow.config.constants import MEETING_TITLE_PREFIX

        if not title:
            title = f"{MEETING_TITLE_PREFIX}{now.strftime('%Y-%m-%d %H:%M')}"

        return cls(
            id=meeting_id,
            title=title,
            project_id=project_id,
            state=MeetingState.CREATED,
            created_at=now,
            metadata=metadata or {},
            asset_path=str(meeting_id),  # Default to meeting ID
            version=1,
        )

    @classmethod
    def from_uuid_str(
        cls,
        uuid_str: str,
        title: str = "",
        params: MeetingLoadParams | None = None,
    ) -> Meeting:
        """Create meeting with existing UUID string.

        Args:
            uuid_str: UUID string for meeting ID.
            title: Meeting title.
            params: Optional load parameters (state, timestamps, etc.).

        Returns:
            Meeting instance with specified ID.
        """
        p = params or MeetingLoadParams()
        meeting_id = MeetingId(UUID(uuid_str))
        return cls(
            id=meeting_id,
            title=title,
            project_id=p.project_id,
            state=p.state,
            created_at=p.created_at or utc_now(),
            started_at=p.started_at,
            ended_at=p.ended_at,
            metadata=p.metadata or {},
            wrapped_dek=p.wrapped_dek,
            asset_path=p.asset_path or uuid_str,
            version=p.version,
        )

    def start_recording(self) -> None:
        """Transition to recording state.

        Raises:
            ValueError: If transition is not valid.
        """
        if not self.state.can_transition_to(MeetingState.RECORDING):
            raise ValueError(f"Cannot start recording from state {self.state.name}")
        self.state = MeetingState.RECORDING
        self.started_at = utc_now()

    def begin_stopping(self) -> None:
        """Transition to stopping state for graceful shutdown.

        This intermediate state allows audio writers and other resources
        to flush and close properly before the meeting is fully stopped.

        Raises:
            ValueError: If transition is not valid.
        """
        if not self.state.can_transition_to(MeetingState.STOPPING):
            raise ValueError(f"Cannot begin stopping from state {self.state.name}")
        self.state = MeetingState.STOPPING

    def stop_recording(self) -> None:
        """Transition to stopped state (from STOPPING).

        Raises:
            ValueError: If transition is not valid.
        """
        if not self.state.can_transition_to(MeetingState.STOPPED):
            raise ValueError(f"Cannot stop recording from state {self.state.name}")
        self.state = MeetingState.STOPPED
        if self.ended_at is None:
            self.ended_at = utc_now()

    def complete(self) -> None:
        """Transition to completed state.

        Raises:
            ValueError: If transition is not valid.
        """
        if not self.state.can_transition_to(MeetingState.COMPLETED):
            raise ValueError(f"Cannot complete from state {self.state.name}")
        self.state = MeetingState.COMPLETED

    def mark_error(self) -> None:
        """Transition to error state."""
        self.state = MeetingState.ERROR

    def add_segment(self, segment: Segment) -> None:
        """Add a transcript segment.

        Args:
            segment: Segment to add.
        """
        self.segments.append(segment)

    def set_summary(self, summary: Summary) -> None:
        """Set the meeting summary.

        Args:
            summary: Summary to set.
        """
        self.summary = summary

    @property
    def duration_seconds(self) -> float:
        """Calculate meeting duration in seconds."""
        if self.ended_at and self.started_at:
            return (self.ended_at - self.started_at).total_seconds()
        if self.started_at:
            return (utc_now() - self.started_at).total_seconds()
        return 0.0

    @property
    def next_segment_id(self) -> int:
        """Get the next available segment ID."""
        return max(s.segment_id for s in self.segments) + 1 if self.segments else 0

    @property
    def segment_count(self) -> int:
        """Number of transcript segments."""
        return len(self.segments)

    @property
    def full_transcript(self) -> str:
        """Concatenate all segment text."""
        return " ".join(s.text for s in self.segments)

    def is_in_active_state(self) -> bool:
        """Check if meeting is in an active state (created or recording).

        Note: STOPPING is not considered active as it's transitioning to stopped.
        """
        return self.state in (MeetingState.CREATED, MeetingState.RECORDING)

    def has_summary(self) -> bool:
        """Check if meeting has a summary."""
        return self.summary is not None
