# =============================================================================
# 企微IT智能服务台 — 坐席模型
# =============================================================================
# 说明：对应数据库 agents 表，存储坐席（IT服务人员）信息
# 坐席状态：online(在线)/offline(离线)/busy(忙碌)
# =============================================================================

import uuid
from datetime import datetime
from typing import Optional

from sqlalchemy import DateTime, Integer, JSON, String
from sqlalchemy.orm import Mapped, mapped_column

from app.database import Base


class Agent(Base):
    """坐席模型 — 对应 agents 表。

    记录坐席的基本信息和状态，用于消息分配和负载管理。

    Attributes:
        id: 坐席唯一标识（UUID，数据库自动生成）
        user_id: 企微用户ID（唯一，关联企微通讯录）
        name: 坐席姓名
        status: 坐席状态（online/offline/busy）
        current_load: 当前服务会话数
        max_load: 最大同时服务数（默认5）
        created_at: 创建时间
        updated_at: 更新时间
    """

    # 表名（必须和架构文档 DDL 一致）
    __tablename__ = "agents"

    # --------------------------------------------------------------------------
    # 字段定义
    # --------------------------------------------------------------------------

    # 主键：UUID，Python端生成（兼容PostgreSQL和SQLite）
    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=lambda: str(uuid.uuid4()),
    )

    # 企微用户ID（唯一，用于关联企微通讯录和登录认证）
    user_id: Mapped[str] = mapped_column(
        String(64),
        unique=True,
        nullable=False,
        comment="企微用户ID（唯一）",
    )

    # 坐席姓名
    name: Mapped[str] = mapped_column(
        String(128),
        nullable=False,
        comment="坐席姓名",
    )

    # 坐席状态（CHECK 约束：只能取三种值）
    # online: 在线，可以接收新的会话分配
    # offline: 离线，不接收任何会话
    # busy: 忙碌，不接收新会话但继续处理已有的
    status: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        default="offline",
        comment="坐席状态: online/offline/busy",
    )

    # 当前服务会话数（分配新会话时 +1，结单时 -1）
    current_load: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=0,
        comment="当前服务会话数",
    )

    # 最大同时服务数（坐席同时处理的会话数上限）
    # 默认5个，可根据坐席能力调整
    max_load: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=5,
        comment="最大同时服务数",
    )

    # 创建时间
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=datetime.now,
        comment="创建时间",
    )

    # 更新时间
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        nullable=False,
        default=datetime.now,
        onupdate=datetime.now,
        comment="更新时间",
    )

    # 角色（admin=组长, agent=坐席）
    # 管理后台需要 admin 角色才能访问，坐席端无限制
    role: Mapped[str] = mapped_column(
        String(20),
        nullable=False,
        default="agent",
        comment="角色：admin=组长, agent=坐席",
    )

    # 技能标签列表（JSON 数组，存储坐席的技能分类）
    # 可选值：电脑/软件/外设/网络/安全/资产/其他
    skill_tags: Mapped[list] = mapped_column(
        JSON,
        nullable=False,
        default=list,
        comment="技能标签列表（电脑/软件/外设/网络/安全/资产/其他）",
    )

    # OTP密钥（用于TOTP动态码验证，为空表示未绑定）
    otp_secret: Mapped[str] = mapped_column(
        String(32),
        nullable=True,
        default=None,
        comment="OTP密钥（Base32编码）",
    )

    # OTP是否启用（admin角色强制启用）
    otp_enabled: Mapped[bool] = mapped_column(
        Integer,
        nullable=False,
        default=0,
        comment="OTP是否启用（0=否, 1=是）",
    )

    # 本地密码哈希（可选，用于本地密码认证）
    # 使用 bcrypt 加密存储，不存储明文密码
    # 当企微验证不可用时，可作为备用认证方式
    # P1 修复: Mapped[Optional[str]] 解决严格模式下 None 赋值报错
    password_hash: Mapped[Optional[str]] = mapped_column(
        String(128),
        nullable=True,
        default=None,
        comment="本地密码哈希（bcrypt）",
    )

    def __repr__(self) -> str:
        """坐席对象的字符串表示，方便调试。"""
        return (
            f"<Agent(id={self.id}, name={self.name}, "
            f"status={self.status}, load={self.current_load}/{self.max_load})>"
        )
