"""GVS-DSDK 数据模型模块

将 SAAS 主服务器的用户表（User）、权限表（Permission）、角色表（Role）、
用户角色关联表（UserRole）、角色权限关联表（RolePermission）、
岗位模板表（PositionTemplate）、岗位模板权限关联表（PositionTemplatePermission）、
人事职务标签表（Position）、员工部门关联表（UserDept）封装为独立的 Django ORM 模型，
供子服务器直接进行跨服务器 ORM 查询。

权限体系四大分层：
    1. 组织人事层：Tenant → Company → Department，员工通过 UserDept 归属部门
    2. 岗位模板层：PositionTemplate + PositionTemplatePermission，权限初始化快照
    3. 角色权限载体层：Role + RolePermission，运行时鉴权实体
    4. 鉴权规则层：操作权限校验（角色汇总）+ 数据权限校验（组织属性）

使用方式（子服务器）：
    from gvsdsdk.models import Permission, Role, UserRole, RolePermission

    # 查询所有启用的用户（需在业务子类中定义具体 User 模型）
    users = User.objects.filter(UserAccountLicense=1)

    # 或配置 DatabaseRouter 后直接使用
    users = User.objects.filter(UserAccountLicense=1)

设计原则：
    1. 独立：不依赖 gvsds 内部模块，可在任意 Django 项目中独立使用
    2. 非托管：managed=False，不创建/迁移表，仅映射已有表结构
    3. PascalCase：字段名、方法名遵循帕斯卡命名法
    4. 兼容：db_table、db_column 与 SAAS 主库完全一致
    5. 租户隔离：所有权限相关数据依附于独立租户空间，不同租户互相不可见

注意：User 为抽象基类，仅包含 SAAS 主库标准字段。
      业务子类应继承 User 并在单独文件中添加业务字段和方法。
      参见 gvsdsdk/business_models.py。
"""

import uuid as _uuid
import datetime as _datetime
from django.db import models
from django.contrib.auth.models import BaseUserManager
from gvsdsdk.model_base import QModel
from gvsdsdk.model_utils import UUIDObj


# === UUID 字段 ===

class FixedBinaryField(models.BinaryField):
    """定长二进制字段：映射 MySQL BINARY(N)，可用于主键"""

    description = "Fixed-length binary field"

    def __init__(self, *args, **kwargs):
        self.binary_length = kwargs.pop('binary_length', 16)
        kwargs.setdefault('max_length', self.binary_length)
        kwargs.setdefault('editable', False)
        super().__init__(*args, **kwargs)

    def db_type(self, connection):
        if connection.vendor == 'mysql':
            return f'BINARY({self.binary_length})'
        elif connection.vendor == 'sqlite':
            return 'BLOB'
        elif connection.vendor == 'postgresql':
            return 'BYTEA'
        return f'BINARY({self.binary_length})'

    def rel_db_type(self, connection):
        return self.db_type(connection)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        kwargs['binary_length'] = self.binary_length
        return name, path, args, kwargs


class UUIDField(FixedBinaryField):
    """UUID 字段：数据库存储为 BINARY(16)，Python 侧自动转换 str/bytes/uuid.UUID"""

    description = "UUID stored as BINARY(16)"

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('max_length', 16)
        kwargs.setdefault('editable', False)
        super().__init__(*args, **kwargs)

    def db_type(self, connection):
        vendor = connection.vendor
        if vendor == 'mysql':
            return 'BINARY(16)'
        elif vendor == 'sqlite':
            return 'BLOB'
        elif vendor == 'postgresql':
            return 'BYTEA'
        return 'BINARY(16)'

    def from_db_value(self, value, expression, connection):
        if value is None:
            return None
        if isinstance(value, UUIDObj):
            return value
        return UUIDObj(value)

    def get_prep_value(self, value):
        if value is None:
            return None
        if isinstance(value, UUIDObj):
            return value.bytes
        if isinstance(value, str):
            try:
                return _uuid.UUID(value).bytes
            except ValueError:
                return None
        if isinstance(value, _uuid.UUID):
            return value.bytes
        if isinstance(value, bytes):
            return value
        return None

    def get_prep_lookup(self, lookup_type, value):
        if lookup_type in ('exact', 'iexact', 'in'):
            if value is None:
                return None
            if lookup_type == 'in' and isinstance(value, (list, tuple)):
                return [self.get_prep_value(v) for v in value]
            return self.get_prep_value(value)
        return super().get_prep_lookup(lookup_type, value)

    def value_to_string(self, obj):
        value = self.value_from_object(obj)
        if isinstance(value, UUIDObj):
            return value.str or ''
        if isinstance(value, str):
            return value
        if isinstance(value, bytes) and len(value) == 16:
            return str(_uuid.UUID(bytes=value))
        if isinstance(value, _uuid.UUID):
            return str(value)
        return ''

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        del kwargs['max_length']
        return name, path, args, kwargs


# === QModel 基础模型 ===

# === 用户管理器 ===

class UserManager(BaseUserManager):
    """用户管理器——提供用户创建与超级用户创建。
    方法名保留蛇形命名以兼容 Django 内部约定。"""

    def create_user(self, username, password=None, email='', **extra_fields):
        """创建普通用户"""
        if not username:
            raise ValueError('The Username field must be set')
        user = self.model(
            UserUUID=_uuid.uuid4().bytes,
            UserName=username,
            UserEmail=email or '',
            **extra_fields
        )
        if password:
            user.SetPassword(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, password=None, **extra_fields):
        """创建超级用户"""
        extra_fields.setdefault('UserAccountLicense', 1)
        extra_fields.setdefault('UserPositionStatus', 0)
        extra_fields.setdefault('IsStaff', True)
        extra_fields.setdefault('IsSuperuser', True)
        return self.create_user(username, password, **extra_fields)


# === 用户表 ===
class User(QModel):
    """用户表——系统核心身份模型（抽象基类，映射 SAAS 主库 User 表标准字段）

    本类为抽象基类，仅包含 SAAS 主库 User 表的标准字段和方法。
    业务子类应继承本类，在单独文件中添加业务字段和方法。
    参见 gvsdsdk/business_models.py。
    """

    UserUUID = UUIDField(primary_key=True, db_column='UserUUID', verbose_name='用户UUID', default=_uuid.uuid4)
    UserName = models.CharField(max_length=256, unique=True, db_column='UserName', verbose_name='用户名')
    UserPassword = models.CharField(max_length=60, default='', db_column='UserPassword', verbose_name='密码')
    UserPositionStatus = models.SmallIntegerField(default=0, db_column='UserPositionStatus', verbose_name='职位状态')
    UserPersonalSignature = models.CharField(max_length=1024, default='', db_column='UserPersonalSignature', verbose_name='个人签名')
    UserEmail = models.CharField(max_length=256, default='', db_column='UserEmail', verbose_name='邮箱')
    UserEmailVerify = models.SmallIntegerField(default=0, db_column='UserEmailVerify', verbose_name='邮箱验证')
    UserAccountLicense = models.SmallIntegerField(default=1, db_column='UserAccountLicense', verbose_name='账户许可')
    UserGender = models.SmallIntegerField(default=-1, db_column='UserGender', verbose_name='性别')
    UserTele = models.CharField(max_length=16, null=True, blank=True, db_column='UserTele', verbose_name='电话')
    UserCreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='UserCreateTime', verbose_name='创建时间')
    UserLastLoginDate = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='UserLastLoginDate', verbose_name='最后登录')

    # Django auth 框架必需（由具体子类覆盖）
    USERNAME_FIELD = 'UserName'
    REQUIRED_FIELDS = []

    class Meta:
        abstract = True

    def __str__(self):
        return self.UserName

    @property
    def UUIDStr(self):
        """返回 UUID 字符串形式"""
        return UUIDObj(self.UserUUID).str

    @property
    def IsActive(self):
        """账户是否启用（UserAccountLicense == 1）"""
        return self.UserAccountLicense == 1

    @property
    def IsOnJob(self):
        """是否在职（UserPositionStatus == 0）"""
        return self.UserPositionStatus == 0

    @property
    def IsAnonymous(self):
        return False

    @property
    def IsAuthenticated(self):
        return True

    @property
    def PK(self):
        return UUIDObj(self.UserUUID)

    @property
    def ID(self):
        return UUIDObj(self.UserUUID)

    def SetPassword(self, RawPassword):
        """设置密码——bcrypt 哈希"""
        import bcrypt
        salt = bcrypt.gensalt(rounds=12)
        hashed = bcrypt.hashpw(RawPassword.encode('utf-8'), salt)
        self.UserPassword = hashed.decode('utf-8')

    def CheckPassword(self, RawPassword):
        """验证密码——兼容 bcrypt 哈希和明文存储"""
        import bcrypt
        stored = self.UserPassword or ''
        # bcrypt 哈希以 $2b$ 或 $2a$ 开头，长度固定 60
        if stored.startswith(('$2b$', '$2a$')) and len(stored) == 60:
            try:
                return bcrypt.checkpw(
                    RawPassword.encode('utf-8'),
                    stored.encode('utf-8')
                )
            except Exception:
                return False
        else:
            # 明文密码（旧数据兼容）
            return stored == RawPassword

    def GetTele(self):
        """获取电话，空则返回默认文本"""
        return self.UserTele or '未填写'

    def GetCompanies(self):
        """获取用户所属公司列表"""
        # Company 模型不在 gvsdsdk 中，此处返回空 QuerySet
        # 如需使用，请在子服务器中自行实现
        return []

    def GetRoles(self):
        """获取用户角色列表（需在同一 database 连接下使用）"""
        user_role_uuids = UserRole.objects.filter(
            UserUUID=self.UserUUID
        ).values_list('RoleUUID', flat=True)
        return Role.objects.filter(RoleUUID__in=user_role_uuids)

    def GetDepartments(self):
        """获取用户部门列表"""
        # Department 模型不在 gvsdsdk 中，此处返回空列表
        # 如需使用，请在子服务器中自行实现
        return []

    def HasPermission(self, PermCode):
        """检查用户是否拥有指定权限（需在同一 database 连接下使用）

        通过 UserRole → RolePermission → Permission 链路查询，
        汇总所有角色的操作权限后判断。
        """
        user_role_uuids = UserRole.objects.filter(
            UserUUID=self.UserUUID
        ).values_list('RoleUUID', flat=True)
        perm_uuids = RolePermission.objects.filter(
            RoleUUID__in=user_role_uuids
        ).values_list('PermUUID', flat=True)
        return Permission.objects.filter(
            PermUUID__in=perm_uuids,
            PermCode=PermCode,
            PermStatus=1,
        ).exists()

    # ── Django auth 框架必需属性 ──
    @property
    def is_active(self):
        return self.IsActive

    @property
    def is_anonymous(self):
        return self.IsAnonymous

    @property
    def is_authenticated(self):
        return self.IsAuthenticated

    @property
    def pk(self):
        return self.PK

    @property
    def id(self):
        return self.ID

    def set_password(self, raw_password):
        self.SetPassword(raw_password)

    def check_password(self, raw_password):
        return self.CheckPassword(raw_password)


# === 用户头像表 ===

class UserAvatar(QModel):
    """用户头像表（映射 SAAS 主库 UserAvatar 表）"""

    UserUUID = UUIDField(primary_key=True, db_column='UserUUID', verbose_name='用户UUID')
    UserAvatar = models.BinaryField(editable=True, db_column='UserAvatar', verbose_name='头像数据')
    AvatarUploadTime = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='AvatarUploadTime', verbose_name='上传时间')
    AvatarFileType = models.CharField(max_length=16, default='png', db_column='AvatarFileType', verbose_name='文件类型')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserAvatar'
        verbose_name = '用户头像'
        verbose_name_plural = '用户头像'


# === 用户双因素认证表 ===

class User2FA(QModel):
    """用户双因素认证表（映射 SAAS 主库 User2FA 表）"""

    User2FAUUID = UUIDField(primary_key=True, db_column='User2FAUUID', verbose_name='2FA UUID')
    UserUUID = UUIDField(db_index=True, db_column='UserUUID', verbose_name='用户UUID')
    SecretKey = models.CharField(max_length=64, db_column='SecretKey', verbose_name='密钥')
    IsEnabled = models.SmallIntegerField(default=0, db_column='IsEnabled', verbose_name='是否启用')
    Verified = models.SmallIntegerField(default=0, db_column='Verified', verbose_name='已验证')
    LastUsedAt = models.DateTimeField(null=True, blank=True, db_column='LastUsedAt', verbose_name='最后使用')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'User2FA'
        verbose_name = '双因素认证'
        verbose_name_plural = '双因素认证'


# === 双因素认证待验证表 ===

class UserPending2FA(QModel):
    """双因素认证待验证表（映射 SAAS 主库 UserPending2FA 表）"""

    PendingUUID = UUIDField(primary_key=True, db_column='PendingUUID', verbose_name='待确认UUID')
    UserUUID = UUIDField(unique=True, db_column='UserUUID', verbose_name='用户UUID')
    SecretKey = models.CharField(max_length=64, db_column='SecretKey', verbose_name='密钥')
    ExpireAt = models.DateTimeField(db_column='ExpireAt', verbose_name='过期时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserPending2FA'
        verbose_name = '2FA待确认'
        verbose_name_plural = '2FA待确认'


# === 临时令牌表 ===

def _EltEndTimeDefault():
    from django.conf import settings
    days = getattr(settings, 'ELT_TOKEN_LIFETIME_DAYS', 30)
    return _datetime.datetime.utcnow() + _datetime.timedelta(days=days)


class EphemeralToken(QModel):
    """临时令牌表——用于 API 认证与会话管理（映射 SAAS 主库 EphemeralToken 表）"""

    ELTUUID = UUIDField(primary_key=True, db_column='ELTUUID', verbose_name='令牌UUID')
    ELTUserUUID = UUIDField(db_index=True, db_column='ELTUserUUID', verbose_name='用户UUID')
    ELTCreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='ELTCreateTime', verbose_name='创建时间')
    ELTEndTime = models.DateTimeField(default=_EltEndTimeDefault, db_column='ELTEndTime', verbose_name='过期时间')
    ELTType = models.SmallIntegerField(default=0, db_column='ELTType', verbose_name='令牌类型')
    ELTAllowIP = models.JSONField(default=list, db_column='ELTAllowIP', verbose_name='允许IP')
    ELTStatus = models.SmallIntegerField(default=1, db_index=True, db_column='ELTStatus', verbose_name='状态')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'EphemeralToken'
        verbose_name = '临时令牌'
        verbose_name_plural = '临时令牌'

    def IsExpired(self):
        """检查令牌是否过期"""
        return _datetime.datetime.utcnow() > self.ELTEndTime.replace(tzinfo=None)

    def IsValid(self):
        """检查令牌是否有效"""
        return self.ELTStatus == 1 and not self.IsExpired()


# === 用户登录日志表 ===

class UserLoginLog(QModel):
    """用户登录日志表（映射 SAAS 主库 UserLoginLog 表）"""

    LogUUID = UUIDField(primary_key=True, db_column='LogUUID', verbose_name='日志UUID')
    UserUUID = UUIDField(db_index=True, db_column='UserUUID', verbose_name='用户UUID')
    LoginIP = models.CharField(max_length=39, db_column='LoginIP', verbose_name='登录IP')
    LoginPlatform = models.CharField(max_length=32, db_column='LoginPlatform', verbose_name='登录平台')
    LoginStatus = models.SmallIntegerField(db_column='LoginStatus', verbose_name='登录状态')
    LoginTime = models.DateTimeField(default=_datetime.datetime.utcnow, db_column='LoginTime', verbose_name='登录时间')
    UserAgent = models.CharField(max_length=512, default='', db_column='UserAgent', verbose_name='用户代理')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserLoginLog'
        verbose_name = '登录日志'
        verbose_name_plural = '登录日志'


# === 账户激活码表 ===

class AccountActivation(QModel):
    """账户激活码表（映射 SAAS 主库 AccountActivation 表）"""

    AccountActivationCode = FixedBinaryField(primary_key=True, binary_length=6, db_column='AccountActivationCode', verbose_name='激活码')
    UserUUID = UUIDField(db_column='UserUUID', verbose_name='用户UUID')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'AccountActivation'
        verbose_name = '账户激活'
        verbose_name_plural = '账户激活'


# === 角色表 ===

class Role(QModel):
    """角色表——权限分配单元（映射 SAAS 主库 Role 表）

    角色是真正承载操作权限的实体，在单个租户内部独立存在，
    不依附任何公司或部门。通过 AssignScope 控制角色的分配可见范围：
      - 0：全租户管理员可分发
      - 1：仅指定公司管理员可分发（AssignScopeUUID = CompanyUUID）
      - 2：仅指定部门管理员可分发（AssignScopeUUID = DeptUUID）
    """

    RoleUUID = UUIDField(primary_key=True, db_column='RoleUUID', verbose_name='角色UUID')
    TenantUUID = UUIDField(db_column='TenantUUID', verbose_name='租户UUID')
    RoleName = models.CharField(max_length=128, db_column='RoleName', verbose_name='角色名称')
    RoleType = models.SmallIntegerField(default=2, db_column='RoleType', verbose_name='角色类型')
    RoleStatus = models.SmallIntegerField(default=1, db_column='RoleStatus', verbose_name='角色状态')
    AssignScope = models.SmallIntegerField(default=0, db_column='AssignScope', verbose_name='分配可见范围')
    AssignScopeUUID = UUIDField(null=True, blank=True, db_column='AssignScopeUUID', verbose_name='分配范围UUID')
    RoleDesc = models.CharField(max_length=512, default='', db_column='RoleDesc', verbose_name='角色描述')
    ClubID = models.CharField(
        max_length=16, default='', blank=True, db_column='club_id',
        db_index=True, verbose_name='所属俱乐部(空=集团全局角色)',
    )
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'Role'
        verbose_name = '角色'
        verbose_name_plural = '角色'

    def __str__(self):
        return self.RoleName

    def GetPermissions(self):
        """获取角色拥有的权限列表（通过 RolePermission 中间表）"""
        perm_uuids = RolePermission.objects.filter(
            RoleUUID=self.RoleUUID
        ).values_list('PermUUID', flat=True)
        return Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1)

    def GetUsers(self):
        """获取拥有该角色的用户列表"""
        from django.apps import apps
        UserModel = apps.get_model('gvsdsdk', 'User')
        user_uuids = UserRole.objects.filter(
            RoleUUID=self.RoleUUID
        ).values_list('UserUUID', flat=True)
        return UserModel.objects.filter(UserUUID__in=user_uuids)


# === 权限表 ===

class Permission(QModel):
    """权限表——操作权限定义（映射 SAAS 主库 Permission 表）

    独立的权限定义表，租户内全局可用，不再挂在角色下。
    通过 RolePermission 中间表与角色建立多对多关系，
    通过 PositionTemplatePermission 中间表与岗位模板建立多对多关系。
    """

    PermUUID = UUIDField(primary_key=True, db_column='PermUUID', verbose_name='权限UUID')
    TenantUUID = UUIDField(db_column='TenantUUID', verbose_name='租户UUID')
    PermName = models.CharField(max_length=128, db_column='PermName', verbose_name='权限名称')
    PermCode = models.CharField(max_length=128, db_column='PermCode', verbose_name='权限键')
    PermCategory = models.CharField(max_length=64, default='', db_column='PermCategory', verbose_name='权限分类')
    PermStatus = models.SmallIntegerField(default=1, db_column='PermStatus', verbose_name='是否启用')
    PermDesc = models.CharField(max_length=512, default='', db_column='PermDesc', verbose_name='描述')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'Permission'
        verbose_name = '权限'
        verbose_name_plural = '权限'

    def __str__(self):
        return f"{self.PermName} ({self.PermCode})"

    def GetRoles(self):
        """获取拥有该权限的角色列表"""
        role_uuids = RolePermission.objects.filter(
            PermUUID=self.PermUUID
        ).values_list('RoleUUID', flat=True)
        return Role.objects.filter(RoleUUID__in=role_uuids)


# === 用户角色关联表 ===

class UserRole(QModel):
    """用户角色关联表——用户与角色的多对多映射（映射 SAAS 主库 UserRole 表）

    通过 CompanyUUID 标识该用户-角色关联所属的公司，
    用于菜单按公司差异化显示、数据权限按公司过滤等场景。
    同一用户在不同公司下可绑定不同角色。

    注意：UserUUID 和 RoleUUID 在 gvsds 中是 ForeignKey，
    但此处改为 UUIDField 以保持独立性。
    """

    UserRoleUUID = UUIDField(primary_key=True, db_column='UserRoleUUID', verbose_name='关联UUID')
    # 原 gvsds 中为 ForeignKey(User)，此处改为 UUIDField
    UserUUID = UUIDField(db_column='UserUUID', verbose_name='用户UUID')
    # 原 gvsds 中为 ForeignKey('Role')，此处改为 UUIDField
    RoleUUID = UUIDField(db_column='RoleUUID', verbose_name='角色UUID')
    CompanyUUID = UUIDField(db_column='CompanyUUID', verbose_name='公司UUID')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserRole'
        verbose_name = '用户角色关联'
        verbose_name_plural = '用户角色关联'


# === 角色权限关联表 ===

class RolePermission(QModel):
    """角色权限关联表——角色与操作权限的多对多映射（映射 SAAS 主库 RolePermission 表）

    一个角色可以拥有多个权限，一个权限也可以被多个角色引用。
    角色和具体操作权限为多对多绑定关系，一套权限集合可以打包在一个角色内统一维护。
    """

    RolePermUUID = UUIDField(primary_key=True, db_column='RolePermUUID', verbose_name='关联UUID')
    RoleUUID = UUIDField(db_column='RoleUUID', verbose_name='角色UUID')
    PermUUID = UUIDField(db_column='PermUUID', verbose_name='权限UUID')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'RolePermission'
        verbose_name = '角色权限关联'
        verbose_name_plural = '角色权限关联'


# === 用户 ABAC 表 ===

class UserABAC(QModel):
    """用户 ABAC 表——基于属性的访问控制（映射 SAAS 主库 UserABAC 表）"""

    UserABACUUID = UUIDField(primary_key=True, db_column='UserABACUUID', verbose_name='ABAC UUID')
    UserUUID = UUIDField(db_column='UserUUID', verbose_name='用户UUID')
    HierarchicalPermissionIdentifiers = models.CharField(max_length=256, db_column='HierarchicalPermissionIdentifiers', verbose_name='层级权限标识')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserABAC'
        verbose_name = '用户ABAC'
        verbose_name_plural = '用户ABAC'


# === 密码表 ===

class Password(QModel):
    """密码表——独立密码存储（映射 SAAS 主库 Password 表）"""

    UserUUID = UUIDField(primary_key=True, db_column='UserUUID', verbose_name='用户UUID')
    Password = models.CharField(max_length=1024, db_column='Password', verbose_name='密码哈希')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'Password'
        verbose_name = '密码'
        verbose_name_plural = '密码'


# === 商铺表 ===

class Shop(QModel):
    """商铺表——SAAS 多商铺体系中的商铺实体

    每个商铺属于一个公司（CompanyUUID），可关联多个角色（通过 RoleShop）。
    """

    ShopUUID = UUIDField(primary_key=True, db_column='ShopUUID', verbose_name='商铺UUID')
    CompanyUUID = UUIDField(db_column='CompanyUUID', verbose_name='公司UUID')
    ShopName = models.CharField(max_length=128, db_column='ShopName', verbose_name='商铺名称')
    ShopCode = models.CharField(max_length=64, default='', db_column='ShopCode', verbose_name='商铺编码')
    ShopType = models.SmallIntegerField(default=0, db_column='ShopType', verbose_name='商铺类型')
    ShopStatus = models.SmallIntegerField(default=1, db_column='ShopStatus', verbose_name='商铺状态')
    ShopAddress = models.CharField(max_length=512, default='', db_column='ShopAddress', verbose_name='商铺地址')
    ShopContact = models.CharField(max_length=128, default='', db_column='ShopContact', verbose_name='联系人')
    ShopPhone = models.CharField(max_length=32, default='', db_column='ShopPhone', verbose_name='联系电话')
    ShopDesc = models.CharField(max_length=512, default='', db_column='ShopDesc', verbose_name='描述')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')
    UpdateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='更新时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'Shop'
        verbose_name = '商铺'
        verbose_name_plural = '商铺'

    def __str__(self):
        return self.ShopName

    def GetRoles(self):
        """获取商铺关联的所有角色"""
        role_uuids = RoleShop.objects.filter(
            ShopUUID=self.ShopUUID
        ).values_list('RoleUUID', flat=True)
        return Role.objects.filter(RoleUUID__in=role_uuids)


# === 角色商铺关联表 ===

class RoleShop(QModel):
    """角色商铺关联表——角色与商铺的多对多映射

    一个角色可以管理多个商铺，一个商铺也可以被多个角色管理。
    """

    RoleShopUUID = UUIDField(primary_key=True, db_column='RoleShopUUID', verbose_name='关联UUID')
    RoleUUID = UUIDField(db_column='RoleUUID', verbose_name='角色UUID')
    ShopUUID = UUIDField(db_column='ShopUUID', verbose_name='商铺UUID')
    IsMainShop = models.SmallIntegerField(default=0, db_column='IsMainShop', verbose_name='主商铺')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'RoleShop'
        verbose_name = '角色商铺关联'
        verbose_name_plural = '角色商铺关联'


# === 岗位模板表 ===

class PositionTemplate(QModel):
    """岗位模板表——权限初始化快照模板（映射 SAAS 主库 PositionTemplate 表）

    租户内全局可重复使用，定位是权限初始化快照模板，
    不直接分配给员工、不参与运行时鉴权。
    新建角色时可一键复制模板内的全部权限内容生成新角色。
    模板后续调整只会作用于之后新创建的角色，
    已有角色不会同步变更，实现模板复用和存量权限独立管控互不干扰。
    """

    PositionTemplateUUID = UUIDField(primary_key=True, db_column='PositionTemplateUUID', verbose_name='岗位模板UUID')
    TenantUUID = UUIDField(db_column='TenantUUID', verbose_name='租户UUID')
    TemplateName = models.CharField(max_length=128, db_column='TemplateName', verbose_name='模板名称')
    TemplateCode = models.CharField(max_length=64, default='', db_column='TemplateCode', verbose_name='模板编码')
    TemplateStatus = models.SmallIntegerField(default=1, db_column='TemplateStatus', verbose_name='模板状态')
    TemplateDesc = models.CharField(max_length=512, default='', db_column='TemplateDesc', verbose_name='模板描述')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')
    UpdateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='更新时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'PositionTemplate'
        verbose_name = '岗位模板'
        verbose_name_plural = '岗位模板'

    def __str__(self):
        return self.TemplateName

    def GetPermissions(self):
        """获取模板关联的权限列表"""
        perm_uuids = PositionTemplatePermission.objects.filter(
            PositionTemplateUUID=self.PositionTemplateUUID
        ).values_list('PermUUID', flat=True)
        return Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1)

    def CopyToRole(self, RoleName, TenantUUID):
        """从模板复制权限到新角色（一次性复制，后续模板变更不影响已有角色）"""
        role = Role.objects.create(
            RoleUUID=_uuid.uuid4().bytes,
            TenantUUID=TenantUUID,
            RoleName=RoleName,
        )
        template_perms = PositionTemplatePermission.objects.filter(
            PositionTemplateUUID=self.PositionTemplateUUID
        )
        for tp in template_perms:
            RolePermission.objects.create(
                RolePermUUID=_uuid.uuid4().bytes,
                RoleUUID=role.RoleUUID,
                PermUUID=tp.PermUUID,
            )
        return role


# === 岗位模板权限关联表 ===

class PositionTemplatePermission(QModel):
    """岗位模板权限关联表——岗位模板与操作权限的多对多映射

    仅作为复制源头，不参与运行时鉴权。
    新建角色时一键复制模板权限到角色，复制后模板与角色无运行时绑定。
    """

    PTPermUUID = UUIDField(primary_key=True, db_column='PTPermUUID', verbose_name='关联UUID')
    PositionTemplateUUID = UUIDField(db_column='PositionTemplateUUID', verbose_name='岗位模板UUID')
    PermUUID = UUIDField(db_column='PermUUID', verbose_name='权限UUID')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'PositionTemplatePermission'
        verbose_name = '岗位模板权限关联'
        verbose_name_plural = '岗位模板权限关联'


# === 人事职务标签表 ===

class Position(QModel):
    """人事职务标签表——仅用于人事管理标注（映射 SAAS 主库 Position 表）

    员工会标注对应的职务标签，该标签仅为人事标注信息，
    不直接绑定权限，和角色、权限体系完全解耦。
    人员调岗、升职只修改组织归属和人事职务标签，权限只需增删绑定角色即可，互不干扰。
    """

    PositionUUID = UUIDField(primary_key=True, db_column='PositionUUID', verbose_name='职务UUID')
    TenantUUID = UUIDField(db_column='TenantUUID', verbose_name='租户UUID')
    PositionName = models.CharField(max_length=128, db_column='PositionName', verbose_name='职务名称')
    PositionCode = models.CharField(max_length=64, default='', db_column='PositionCode', verbose_name='职务编码')
    PositionLevel = models.SmallIntegerField(default=0, db_column='PositionLevel', verbose_name='职务级别')
    PositionStatus = models.SmallIntegerField(default=1, db_column='PositionStatus', verbose_name='状态')
    PositionDesc = models.CharField(max_length=512, default='', db_column='PositionDesc', verbose_name='描述')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')
    UpdateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='更新时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'Position'
        verbose_name = '人事职务标签'
        verbose_name_plural = '人事职务标签'

    def __str__(self):
        return self.PositionName


# === 员工部门关联表 ===

class UserDept(QModel):
    """员工部门关联表——员工与部门的多对多映射（映射 SAAS 主库 UserDept 表）

    支持一人多部门兼职，同时标注该员工在对应部门的职务标签。
    该层级仅用于组织架构展示、审批流转、人员统计，
    同时为数据权限判断提供人员所属组织属性依据，不参与操作权限校验。
    """

    UserDeptUUID = UUIDField(primary_key=True, db_column='UserDeptUUID', verbose_name='关联UUID')
    UserUUID = UUIDField(db_column='UserUUID', verbose_name='用户UUID')
    DeptUUID = UUIDField(db_column='DeptUUID', verbose_name='部门UUID')
    PositionUUID = UUIDField(null=True, blank=True, db_column='PositionUUID', verbose_name='职务标签UUID')
    IsMainDept = models.SmallIntegerField(default=1, db_column='IsMainDept', verbose_name='是否主部门')
    CreateTime = models.DateTimeField(default=_datetime.datetime.utcnow, verbose_name='创建时间')

    class Meta:
        managed = True
        app_label = 'gvsdsdk'
        db_table = 'UserDept'
        verbose_name = '员工部门关联'
        verbose_name_plural = '员工部门关联'
