"""Core meeting domain models."""

from __future__ import annotations

from datetime import datetime
from typing import TYPE_CHECKING
from uuid import UUID as PyUUID
from uuid import uuid4

from pgvector.sqlalchemy import Vector
from sqlalchemy import (
    DateTime,
    Float,
    ForeignKey,
    Integer,
    LargeBinary,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from noteflow.domain.utils.time import utc_now

from .._base import DEFAULT_USER_ID, DEFAULT_WORKSPACE_ID, EMBEDDING_DIM, Base

if TYPE_CHECKING:
    from noteflow.infrastructure.persistence.models.core.annotation import AnnotationModel
    from noteflow.infrastructure.persistence.models.core.diarization import (
        DiarizationJobModel,
        StreamingDiarizationTurnModel,
    )
    from noteflow.infrastructure.persistence.models.core.summary import SummaryModel
    from noteflow.infrastructure.persistence.models.entities.named_entity import (
        NamedEntityModel,
    )
    from noteflow.infrastructure.persistence.models.entities.speaker import (
        MeetingSpeakerModel,
    )
    from noteflow.infrastructure.persistence.models.identity.identity import (
        ProjectModel,
        UserModel,
        WorkspaceModel,
    )
    from noteflow.infrastructure.persistence.models.integrations.integration import (
        MeetingCalendarLinkModel,
    )
    from noteflow.infrastructure.persistence.models.organization.tagging import (
        MeetingTagModel,
    )
    from noteflow.infrastructure.persistence.models.organization.task import TaskModel


class MeetingModel(Base):
    """Represent a meeting recording session."""

    __tablename__ = "meetings"
    __table_args__: dict[str, str] = {"schema": "noteflow"}

    id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )
    # Forward-looking tenancy fields with safe defaults for current single-user mode
    workspace_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.workspaces.id", ondelete="RESTRICT"),
        nullable=False,
        default=lambda: PyUUID(DEFAULT_WORKSPACE_ID),
    )
    created_by_id: Mapped[PyUUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.users.id", ondelete="SET NULL"),
        nullable=True,
        default=lambda: PyUUID(DEFAULT_USER_ID),
    )
    # Optional project scoping (scope lattice: workspace → project → meeting)
    project_id: Mapped[PyUUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.projects.id", ondelete="SET NULL"),
        nullable=True,
    )

    title: Mapped[str] = mapped_column(String(255), nullable=False)
    state: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )
    started_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    ended_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    metadata_: Mapped[dict[str, object]] = mapped_column(
        "metadata",
        JSONB,
        nullable=False,
        default=dict,
    )
    wrapped_dek: Mapped[bytes | None] = mapped_column(
        LargeBinary,
        nullable=True,
    )
    asset_path: Mapped[str | None] = mapped_column(
        Text,
        nullable=True,
    )
    version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
    # Soft delete support
    deleted_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )

    # Relationships
    workspace: Mapped[WorkspaceModel] = relationship(
        "WorkspaceModel",
        back_populates="meetings",
    )
    created_by: Mapped[UserModel | None] = relationship(
        "UserModel",
        back_populates="created_meetings",
        foreign_keys=[created_by_id],
    )
    project: Mapped[ProjectModel | None] = relationship(
        "ProjectModel",
        back_populates="meetings",
    )
    segments: Mapped[list[SegmentModel]] = relationship(
        "SegmentModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
        lazy="selectin",
    )
    summary: Mapped[SummaryModel | None] = relationship(
        "SummaryModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
        uselist=False,
        lazy="selectin",
    )
    annotations: Mapped[list[AnnotationModel]] = relationship(
        "AnnotationModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
        lazy="selectin",
    )
    diarization_jobs: Mapped[list[DiarizationJobModel]] = relationship(
        "DiarizationJobModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )
    streaming_turns: Mapped[list[StreamingDiarizationTurnModel]] = relationship(
        "StreamingDiarizationTurnModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )
    speakers: Mapped[list[MeetingSpeakerModel]] = relationship(
        "MeetingSpeakerModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )
    meeting_tags: Mapped[list[MeetingTagModel]] = relationship(
        "MeetingTagModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )
    tasks: Mapped[list[TaskModel]] = relationship(
        "TaskModel",
        back_populates="meeting",
    )
    calendar_links: Mapped[list[MeetingCalendarLinkModel]] = relationship(
        "MeetingCalendarLinkModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )
    named_entities: Mapped[list[NamedEntityModel]] = relationship(
        "NamedEntityModel",
        back_populates="meeting",
        cascade="all, delete-orphan",
    )


class SegmentModel(Base):
    """Represent a transcript segment within a meeting."""

    __tablename__ = "segments"
    __table_args__: tuple[UniqueConstraint, dict[str, str]] = (
        UniqueConstraint("meeting_id", "segment_id", name="segments_unique_per_meeting"),
        {"schema": "noteflow"},
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    meeting_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.meetings.id", ondelete="CASCADE"),
        nullable=False,
    )
    segment_id: Mapped[int] = mapped_column(Integer, nullable=False)
    text: Mapped[str] = mapped_column(Text, nullable=False)
    start_time: Mapped[float] = mapped_column(Float, nullable=False)
    end_time: Mapped[float] = mapped_column(Float, nullable=False)
    language: Mapped[str] = mapped_column(String(10), nullable=False, default="en")
    language_confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
    avg_logprob: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
    no_speech_prob: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
    embedding: Mapped[list[float] | None] = mapped_column(
        Vector(EMBEDDING_DIM),
        nullable=True,
    )
    speaker_id: Mapped[str | None] = mapped_column(String(50), nullable=True)
    speaker_confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )

    # Relationships
    meeting: Mapped[MeetingModel] = relationship(
        "MeetingModel",
        back_populates="segments",
    )
    words: Mapped[list[WordTimingModel]] = relationship(
        "WordTimingModel",
        back_populates="segment",
        cascade="all, delete-orphan",
        lazy="selectin",
    )


class WordTimingModel(Base):
    """Represent word-level timing within a segment."""

    __tablename__ = "word_timings"
    __table_args__: tuple[UniqueConstraint, dict[str, str]] = (
        UniqueConstraint("segment_pk", "word_index", name="word_timings_unique_per_segment"),
        {"schema": "noteflow"},
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    segment_pk: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("noteflow.segments.id", ondelete="CASCADE"),
        nullable=False,
    )
    word_index: Mapped[int] = mapped_column(Integer, nullable=False)
    word: Mapped[str] = mapped_column(String(255), nullable=False)
    start_time: Mapped[float] = mapped_column(Float, nullable=False)
    end_time: Mapped[float] = mapped_column(Float, nullable=False)
    probability: Mapped[float] = mapped_column(Float, nullable=False)

    # Relationships
    segment: Mapped[SegmentModel] = relationship(
        "SegmentModel",
        back_populates="words",
    )
