"""Identity and tenancy models for multi-user support."""

from __future__ import annotations

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

from sqlalchemy import DateTime, ForeignKey, 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 Base

if TYPE_CHECKING:
    from noteflow.infrastructure.persistence.models.core.meeting import MeetingModel
    from noteflow.infrastructure.persistence.models.entities.speaker import PersonModel
    from noteflow.infrastructure.persistence.models.integrations.webhook import (
        WebhookConfigModel,
    )
    from noteflow.infrastructure.persistence.models.organization.tagging import TagModel
    from noteflow.infrastructure.persistence.models.organization.task import TaskModel


class WorkspaceModel(Base):
    """Represent a workspace for multi-tenant support."""

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

    id: Mapped[PyUUID] = mapped_column(UUID(as_uuid=True), primary_key=True)
    slug: Mapped[str | None] = mapped_column(Text, unique=True, nullable=True)
    name: Mapped[str] = mapped_column(Text, nullable=False)
    is_default: Mapped[bool] = mapped_column(
        nullable=False,
        default=False,
    )
    settings: 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,
    )
    metadata_: Mapped[dict[str, object]] = mapped_column(
        "metadata",
        JSONB,
        nullable=False,
        default=dict,
    )

    # Relationships
    memberships: Mapped[list[WorkspaceMembershipModel]] = relationship(
        "WorkspaceMembershipModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    meetings: Mapped[list[MeetingModel]] = relationship(
        "MeetingModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    projects: Mapped[list[ProjectModel]] = relationship(
        "ProjectModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    persons: Mapped[list[PersonModel]] = relationship(
        "PersonModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    tags: Mapped[list[TagModel]] = relationship(
        "TagModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    tasks: Mapped[list[TaskModel]] = relationship(
        "TaskModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )
    webhook_configs: Mapped[list[WebhookConfigModel]] = relationship(
        "WebhookConfigModel",
        back_populates="workspace",
        cascade="all, delete-orphan",
    )


class UserModel(Base):
    """Represent a user account."""

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

    id: Mapped[PyUUID] = mapped_column(UUID(as_uuid=True), primary_key=True)
    email: Mapped[str | None] = mapped_column(Text, unique=True, nullable=True)
    display_name: Mapped[str] = mapped_column(Text, 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,
    )
    metadata_: Mapped[dict[str, object]] = mapped_column(
        "metadata",
        JSONB,
        nullable=False,
        default=dict,
    )

    # Relationships
    memberships: Mapped[list[WorkspaceMembershipModel]] = relationship(
        "WorkspaceMembershipModel",
        back_populates="user",
        cascade="all, delete-orphan",
    )
    project_memberships: Mapped[list[ProjectMembershipModel]] = relationship(
        "ProjectMembershipModel",
        back_populates="user",
        cascade="all, delete-orphan",
    )
    created_meetings: Mapped[list[MeetingModel]] = relationship(
        "MeetingModel",
        back_populates="created_by",
        foreign_keys="MeetingModel.created_by_id",
    )


class WorkspaceMembershipModel(Base):
    """Represent workspace membership with role."""

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

    workspace_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.workspaces.id", ondelete="CASCADE"),
        primary_key=True,
    )
    user_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.users.id", ondelete="CASCADE"),
        primary_key=True,
    )
    role: Mapped[str] = mapped_column(String(50), nullable=False, default="owner")
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )

    # Relationships
    workspace: Mapped[WorkspaceModel] = relationship(
        "WorkspaceModel",
        back_populates="memberships",
    )
    user: Mapped[UserModel] = relationship(
        "UserModel",
        back_populates="memberships",
    )


class ProjectModel(Base):
    """Represent a project within a workspace."""

    __tablename__ = "projects"
    __table_args__: tuple[object, ...] = (
        # Unique slug per workspace
        UniqueConstraint("workspace_id", "slug", name="uq_projects_workspace_slug"),
        {"schema": "noteflow"},
    )

    id: Mapped[PyUUID] = mapped_column(UUID(as_uuid=True), primary_key=True)
    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)
    slug: Mapped[str | None] = mapped_column(Text, nullable=True)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_default: Mapped[bool] = mapped_column(nullable=False, default=False)
    settings: 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,
    )
    archived_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True),
        nullable=True,
    )
    metadata_: Mapped[dict[str, object]] = mapped_column(
        "metadata",
        JSONB,
        nullable=False,
        default=dict,
    )

    # Relationships
    workspace: Mapped[WorkspaceModel] = relationship(
        "WorkspaceModel",
        back_populates="projects",
    )
    memberships: Mapped[list[ProjectMembershipModel]] = relationship(
        "ProjectMembershipModel",
        back_populates="project",
        cascade="all, delete-orphan",
    )
    meetings: Mapped[list[MeetingModel]] = relationship(
        "MeetingModel",
        back_populates="project",
    )


class ProjectMembershipModel(Base):
    """Represent project membership with role."""

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

    project_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.projects.id", ondelete="CASCADE"),
        primary_key=True,
    )
    user_id: Mapped[PyUUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("noteflow.users.id", ondelete="CASCADE"),
        primary_key=True,
    )
    role: Mapped[str] = mapped_column(String(50), nullable=False, default="viewer")
    joined_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=utc_now,
    )

    # Relationships
    project: Mapped[ProjectModel] = relationship(
        "ProjectModel",
        back_populates="memberships",
    )
    user: Mapped[UserModel] = relationship(
        "UserModel",
        back_populates="project_memberships",
    )
