from typing import TYPE_CHECKING, Union
from uuid import UUID

from sqlalchemy.schema import Column, ForeignKey, UniqueConstraint
from sqlmodel import Field, Relationship
from sqlmodel.sql.sqltypes import GUID

from joj.horse.models.base import BaseORMModel
from joj.horse.models.domain import Domain
from joj.horse.models.domain_role import DomainRole
from joj.horse.models.permission import DefaultRole
from joj.horse.utils.errors import BizError, ErrorCode

if TYPE_CHECKING:
    from joj.horse.models.user import User


class DomainUser(BaseORMModel, table=True):  # type: ignore[call-arg]
    __tablename__ = "domain_users"
    __table_args__ = (UniqueConstraint("domain_id", "user_id"),)

    role: str

    domain_id: UUID = Field(
        sa_column=Column(
            GUID, ForeignKey("domains.id", ondelete="CASCADE"), nullable=False
        )
    )
    domain: "Domain" = Relationship(back_populates="users")

    user_id: UUID = Field(
        sa_column=Column(
            GUID, ForeignKey("users.id", ondelete="CASCADE"), nullable=False
        )
    )
    user: "User" = Relationship(back_populates="domain_users")

    @classmethod
    async def add_domain_user(
        cls, domain_id: UUID, user_id: UUID, role: Union[str, DefaultRole]
    ) -> "DomainUser":
        role = str(role)
        # check domain user
        domain_user = await DomainUser.get_or_none(domain_id=domain_id, user_id=user_id)
        if domain_user is not None:
            raise BizError(ErrorCode.UserAlreadyInDomainBadRequestError)
        # check domain role
        await DomainRole.ensure_exists(domain_id=domain_id, role=role)
        # add member
        domain_user = DomainUser(domain_id=domain_id, user_id=user_id, role=role)
        return domain_user

    @classmethod
    async def update_domain_user(
        cls, domain_id: UUID, user_id: UUID, role: Union[str, DefaultRole]
    ) -> "DomainUser":
        role = str(role)
        # check domain user
        domain_user = await DomainUser.get_or_none(domain_id=domain_id, user_id=user_id)
        if domain_user is None:
            raise BizError(ErrorCode.UserAlreadyInDomainBadRequestError)
        # check domain role
        await DomainRole.ensure_exists(domain_id=domain_id, role=role)
        # update role
        domain_user.role = role
        return domain_user

sqlalchemy.schema.ForeignKey sqlalchemy.schema.UniqueConstraint joj.horse.utils.errors.BizError joj.horse.models.domain_role.DomainRole.ensure_exists sqlmodel.Relationship
[((883, 919), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""users"""'}), "(back_populates='users')\n", (895, 919), False, 'from sqlmodel import Field, Relationship\n'), ((1086, 1129), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""domain_users"""'}), "(back_populates='domain_users')\n", (1098, 1129), False, 'from sqlmodel import Field, Relationship\n'), ((651, 691), 'sqlalchemy.schema.UniqueConstraint', 'UniqueConstraint', (['"""domain_id"""', '"""user_id"""'], {}), "('domain_id', 'user_id')\n", (667, 691), False, 'from sqlalchemy.schema import Column, ForeignKey, UniqueConstraint\n'), ((1473, 1527), 'joj.horse.utils.errors.BizError', 'BizError', (['ErrorCode.UserAlreadyInDomainBadRequestError'], {}), '(ErrorCode.UserAlreadyInDomainBadRequestError)\n', (1481, 1527), False, 'from joj.horse.utils.errors import BizError, ErrorCode\n'), ((1570, 1626), 'joj.horse.models.domain_role.DomainRole.ensure_exists', 'DomainRole.ensure_exists', ([], {'domain_id': 'domain_id', 'role': 'role'}), '(domain_id=domain_id, role=role)\n', (1594, 1626), False, 'from joj.horse.models.domain_role import DomainRole\n'), ((2099, 2153), 'joj.horse.utils.errors.BizError', 'BizError', (['ErrorCode.UserAlreadyInDomainBadRequestError'], {}), '(ErrorCode.UserAlreadyInDomainBadRequestError)\n', (2107, 2153), False, 'from joj.horse.utils.errors import BizError, ErrorCode\n'), ((2196, 2252), 'joj.horse.models.domain_role.DomainRole.ensure_exists', 'DomainRole.ensure_exists', ([], {'domain_id': 'domain_id', 'role': 'role'}), '(domain_id=domain_id, role=role)\n', (2220, 2252), False, 'from joj.horse.models.domain_role import DomainRole\n'), ((783, 827), 'sqlalchemy.schema.ForeignKey', 'ForeignKey', (['"""domains.id"""'], {'ondelete': '"""CASCADE"""'}), "('domains.id', ondelete='CASCADE')\n", (793, 827), False, 'from sqlalchemy.schema import Column, ForeignKey, UniqueConstraint\n'), ((992, 1034), 'sqlalchemy.schema.ForeignKey', 'ForeignKey', (['"""users.id"""'], {'ondelete': '"""CASCADE"""'}), "('users.id', ondelete='CASCADE')\n", (1002, 1034), False, 'from sqlalchemy.schema import Column, ForeignKey, UniqueConstraint\n')]