"""Integration and calendar 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 sqlalchemy import (
    CheckConstraint,
    DateTime,
    ForeignKey,
    Integer,
    LargeBinary,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import ARRAY, JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from noteflow.domain.utils.time import utc_now

from .._base import Base

if TYPE_CHECKING:
    from noteflow.infrastructure.persistence.models.core.meeting import MeetingModel
    from noteflow.infrastructure.persistence.models.identity.identity import (
        WorkspaceModel,
    )


class IntegrationModel(Base):
    """Represent an external service integration."""

    __tablename__ = "integrations"
    __table_args__: tuple[CheckConstraint, CheckConstraint, dict[str, str]] = (
        CheckConstraint(
            "type IN ('auth', 'email', 'calendar', 'pkm', 'custom')",
            name="integrations_type_chk",
        ),
        CheckConstraint(
            "status IN ('disconnected', 'connected', 'error')",
            name="integrations_status_chk",
        ),
        {"schema": "noteflow"},
    )

    id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )
    workspace_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.workspaces.id", ondelete="CASCADE"),
        nullable=False,
    )
    name: Mapped[str] = mapped_column(Text, nullable=False)
    type: Mapped[str] = mapped_column(Text, nullable=False)
    status: Mapped[str] = mapped_column(Text, nullable=False, default="disconnected")
    config: Mapped[dict[str, object]] = mapped_column(
        JSONB,
        nullable=False,
        default=dict,
    )
    last_sync: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
        onupdate=utc_now,
    )

    # Relationships
    workspace: Mapped[WorkspaceModel] = relationship("WorkspaceModel")
    secrets: Mapped[list[IntegrationSecretModel]] = relationship(
        "IntegrationSecretModel",
        back_populates="integration",
        cascade="all, delete-orphan",
    )
    sync_runs: Mapped[list[IntegrationSyncRunModel]] = relationship(
        "IntegrationSyncRunModel",
        back_populates="integration",
        cascade="all, delete-orphan",
    )
    calendar_events: Mapped[list[CalendarEventModel]] = relationship(
        "CalendarEventModel",
        back_populates="integration",
        cascade="all, delete-orphan",
    )
    external_refs: Mapped[list[ExternalRefModel]] = relationship(
        "ExternalRefModel",
        back_populates="integration",
        cascade="all, delete-orphan",
    )


class IntegrationSecretModel(Base):
    """Store encrypted secrets for an integration."""

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

    integration_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.integrations.id", ondelete="CASCADE"),
        primary_key=True,
    )
    secret_key: Mapped[str] = mapped_column(Text, primary_key=True)
    secret_value: Mapped[bytes] = mapped_column(LargeBinary, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
        onupdate=utc_now,
    )

    # Relationships
    integration: Mapped[IntegrationModel] = relationship(
        "IntegrationModel",
        back_populates="secrets",
    )


class IntegrationSyncRunModel(Base):
    """Track sync operation history for an integration."""

    __tablename__ = "integration_sync_runs"
    __table_args__: tuple[CheckConstraint, dict[str, str]] = (
        CheckConstraint(
            "status IN ('running', 'success', 'error')",
            name="integration_sync_runs_status_chk",
        ),
        {"schema": "noteflow"},
    )

    id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )
    integration_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.integrations.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    status: Mapped[str] = mapped_column(Text, nullable=False)
    started_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )
    ended_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    duration_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
    error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
    stats: Mapped[dict[str, object]] = mapped_column(
        JSONB,
        nullable=False,
        default=dict,
    )

    # Relationships
    integration: Mapped[IntegrationModel] = relationship(
        "IntegrationModel",
        back_populates="sync_runs",
    )


class CalendarEventModel(Base):
    """Cache calendar event data from an integration."""

    __tablename__ = "calendar_events"
    __table_args__: tuple[UniqueConstraint, dict[str, str]] = (
        UniqueConstraint(
            "integration_id",
            "external_id",
            name="calendar_events_unique_external_id",
        ),
        {"schema": "noteflow"},
    )

    id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )
    integration_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.integrations.id", ondelete="CASCADE"),
        nullable=False,
    )
    external_id: Mapped[str] = mapped_column(Text, nullable=False)
    calendar_id: Mapped[str] = mapped_column(Text, nullable=False)
    calendar_name: Mapped[str] = mapped_column(Text, nullable=False)
    title: Mapped[str] = mapped_column(Text, nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    start_time: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
    )
    end_time: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
    )
    location: Mapped[str | None] = mapped_column(Text, nullable=True)
    attendees: Mapped[list[str] | None] = mapped_column(ARRAY(Text), nullable=True)
    is_all_day: Mapped[bool] = mapped_column(default=False)
    meeting_link: Mapped[str | None] = mapped_column(Text, nullable=True)
    raw: Mapped[dict[str, object]] = mapped_column(
        JSONB,
        nullable=False,
        default=dict,
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
        onupdate=utc_now,
    )

    # Relationships
    integration: Mapped[IntegrationModel] = relationship(
        "IntegrationModel",
        back_populates="calendar_events",
    )
    meeting_links: Mapped[list[MeetingCalendarLinkModel]] = relationship(
        "MeetingCalendarLinkModel",
        back_populates="calendar_event",
        cascade="all, delete-orphan",
    )


class MeetingCalendarLinkModel(Base):
    """Junction table linking meetings to calendar events."""

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

    meeting_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.meetings.id", ondelete="CASCADE"),
        primary_key=True,
    )
    calendar_event_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.calendar_events.id", ondelete="CASCADE"),
        primary_key=True,
    )

    # Relationships
    meeting: Mapped[MeetingModel] = relationship(
        "MeetingModel",
        back_populates="calendar_links",
    )
    calendar_event: Mapped[CalendarEventModel] = relationship(
        "CalendarEventModel",
        back_populates="meeting_links",
    )


class ExternalRefModel(Base):
    """Track references to external entities (generic ID mapping)."""

    __tablename__ = "external_refs"
    __table_args__: tuple[UniqueConstraint, dict[str, str]] = (
        UniqueConstraint(
            "integration_id",
            "entity_type",
            "entity_id",
            name="external_refs_unique_entity",
        ),
        {"schema": "noteflow"},
    )

    id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )
    integration_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.integrations.id", ondelete="CASCADE"),
        nullable=False,
    )
    entity_type: Mapped[str] = mapped_column(Text, nullable=False)
    entity_id: Mapped[str] = mapped_column(Text, nullable=False)
    external_id: Mapped[str] = mapped_column(Text, nullable=False)
    external_url: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )

    # Relationships
    integration: Mapped[IntegrationModel] = relationship(
        "IntegrationModel",
        back_populates="external_refs",
    )
