import datetime
import hashlib
import secrets
import uuid
from typing import List, Optional

from sqlalchemy.orm import Session

from app.config.default_ontology_initializer import DefaultOntologyInitializer
from app.core.config import settings
from app.core.error_codes import BizCode
from app.core.exceptions import BusinessException, PermissionDeniedException
from app.core.logging_config import get_business_logger
from app.models.user_model import User
from app.models.workspace_model import (
    InviteStatus,
    Workspace,
    WorkspaceMember,
    WorkspaceRole,
)
from app.repositories import workspace_repository
from app.repositories.workspace_invite_repository import WorkspaceInviteRepository
from app.schemas.workspace_schema import (
    InviteAcceptRequest,
    InviteValidateResponse,
    WorkspaceCreate,
    WorkspaceInviteCreate,
    WorkspaceInviteResponse,
    WorkspaceMemberUpdate,
    WorkspaceModelsUpdate,
    WorkspaceUpdate,
)

# 获取业务逻辑专用日志器
business_logger = get_business_logger()


def switch_workspace(
        db: Session,
        workspace_id: uuid.UUID,
        user: User,
):
    """切换工作空间"""
    business_logger.debug(f"用户 {user.username} 请求切换工作空间为 {workspace_id}")

    # 检查用户是否为成员或超级管理员
    _check_workspace_member_permission(db, workspace_id, user)

    # 更新当前用户的工作空间上下文
    try:
        user.current_workspace_id = workspace_id
        db.commit()
        business_logger.info(f"用户 {user.username} 成功切换工作空间为 {workspace_id}")
        return
    except Exception as e:
        db.rollback()
        business_logger.error(f"切换工作空间失败 - 工作空间: {workspace_id}, 错误: {str(e)}")
        raise BusinessException(f"切换工作空间失败: {str(e)}", BizCode.INTERNAL_ERROR)


def delete_workspace_member(
        db: Session,
        workspace_id: uuid.UUID,
        member_id: uuid.UUID,
        user: User,
):
    """删除工作空间成员"""
    business_logger.debug(f"用户 {user.username} 请求删除工作空间 {workspace_id} 的成员 {member_id}")
    _check_workspace_admin_permission(db, workspace_id, user)
    workspace_member = workspace_repository.get_member_by_id(db=db, member_id=member_id)
    if not workspace_member:
        raise BusinessException(f"工作空间成员 {member_id} 不存在", BizCode.WORKSPACE_NOT_FOUND)

    if workspace_member.workspace_id != workspace_id:
        raise BusinessException(f"工作空间成员 {member_id} 不存在于工作空间 {workspace_id}",
                                BizCode.WORKSPACE_NOT_FOUND)

    try:
        workspace_member.is_active = False
        workspace_member.user.current_workspace_id = None
        db.commit()
        business_logger.info(f"用户 {user.username} 成功删除工作空间 {workspace_id} 的成员 {member_id}")
    except Exception as e:
        db.rollback()
        business_logger.error(f"删除工作空间成员失败 - 工作空间: {workspace_id}, 成员: {member_id}, 错误: {str(e)}")
        raise BusinessException(f"删除工作空间成员失败: {str(e)}", BizCode.INTERNAL_ERROR)


def get_user_workspaces(db: Session, user: User) -> List[Workspace]:
    """获取当前用户参与的所有工作空间
    
    For neo4j storage type workspaces, ensures each has a default memory config.
    If a workspace is missing a default config, one will be created automatically.
    
    Args:
        db: Database session
        user: Current user
        
    Returns:
        List[Workspace]: List of workspaces the user belongs to
    """
    business_logger.debug(f"获取用户工作空间列表: {user.username} (ID: {user.id})")
    workspaces = workspace_repository.get_workspaces_by_user(db=db, user_id=user.id)

    # Ensure each neo4j workspace has a default memory config
    for workspace in workspaces:
        if workspace.storage_type == 'neo4j':
            _ensure_default_memory_config(db, workspace)
            _ensure_default_ontology_scenes(db, workspace)

    business_logger.info(f"用户 {user.username} 的工作空间数量: {len(workspaces)}")
    return workspaces


def _create_workspace_only(
        db: Session, workspace: WorkspaceCreate, owner: User
) -> Workspace:
    business_logger.debug(f"创建工作空间: {workspace.name}, 创建者: {owner.username}")

    try:
        # Create the workspace without adding any members
        business_logger.debug(f"创建工作空间: {workspace.name}")
        db_workspace = workspace_repository.create_workspace(
            db=db, workspace=workspace, tenant_id=owner.tenant_id
        )
        business_logger.info(f"工作空间创建成功: {db_workspace.name} (ID: {db_workspace.id}), 创建者: {owner.username}")
        return db_workspace
    except Exception as e:
        business_logger.error(f"创建工作空间失败: {workspace.name} - {str(e)}")
        raise


def create_workspace(
        db: Session, workspace: WorkspaceCreate, user: User, language: str = "zh"
) -> Workspace:
    business_logger.info(
        f"创建工作空间: {workspace.name}, 创建者: {user.username}, "
        f"storage_type: {workspace.storage_type}"
    )
    if workspace_repository.get_workspaces_by_name(db=db, name=workspace.name, tenant_id=user.tenant_id):
        raise BusinessException(
            message="同名工作空间已存在",
            code=BizCode.RESOURCE_ALREADY_EXISTS
        )
    llm = workspace.llm
    embedding = workspace.embedding
    rerank = workspace.rerank
    try:
        # Create the workspace without adding any members
        business_logger.debug(f"创建工作空间: {workspace.name}")
        db_workspace = workspace_repository.create_workspace(
            db=db, workspace=workspace, tenant_id=user.tenant_id
        )
        business_logger.info(f"工作空间创建成功: {db_workspace.name} (ID: {db_workspace.id}), 创建者: {user.username}")
        db.flush()  # 使用 flush 而不是 commit，获取 ID 但不提交事务
        db.refresh(db_workspace)

        # Initialize default ontology scenes for the workspace (先创建本体场景)
        default_scene_id = None
        default_scene_name = None
        try:
            initializer = DefaultOntologyInitializer(db)
            success, error_msg = initializer.initialize_default_scenes(
                db_workspace.id, language=language
            )

            if success:
                business_logger.info(
                    f"为工作空间 {db_workspace.id} 创建默认本体场景成功 (language={language})"
                )

                # 获取默认场景ID，优先使用"在线教育"场景，如果不存在则使用"情感陪伴"场景
                from app.repositories.ontology_scene_repository import OntologySceneRepository
                from app.config.default_ontology_config import (
                    ONLINE_EDUCATION_SCENE,
                    EMOTIONAL_COMPANION_SCENE,
                    get_scene_name
                )

                scene_repo = OntologySceneRepository(db)

                # 优先尝试获取教育场景
                education_scene_name = get_scene_name(ONLINE_EDUCATION_SCENE, language)
                education_scene = scene_repo.get_by_name(education_scene_name, db_workspace.id)

                if education_scene:
                    default_scene_id = education_scene.scene_id
                    default_scene_name = education_scene.scene_name
                    business_logger.info(
                        f"获取到教育场景ID用于默认记忆配置: {default_scene_id} (scene_name={education_scene_name})"
                    )
                else:
                    # 如果教育场景不存在，尝试获取情感陪伴场景
                    companion_scene_name = get_scene_name(EMOTIONAL_COMPANION_SCENE, language)
                    companion_scene = scene_repo.get_by_name(companion_scene_name, db_workspace.id)

                    if companion_scene:
                        default_scene_id = companion_scene.scene_id
                        default_scene_name = companion_scene.scene_name
                        business_logger.info(
                            f"教育场景不存在，使用情感陪伴场景ID用于默认记忆配置: {default_scene_id} (scene_name={companion_scene_name})"
                        )
                    else:
                        business_logger.warning(
                            f"未找到任何默认场景 (education={education_scene_name}, companion={companion_scene_name})"
                        )
            else:
                business_logger.warning(
                    f"为工作空间 {db_workspace.id} 创建默认本体场景失败: {error_msg} (language={language})"
                )
        except Exception as ontology_error:
            business_logger.error(
                f"为工作空间 {db_workspace.id} 创建默认本体场景异常: {str(ontology_error)} (language={language})"
            )
            # Don't fail workspace creation if default ontology initialization fails
            # The workspace can still function without default ontology scenes

        # Create default memory config for the workspace (only for neo4j storage types)
        # 将默认场景ID（教育场景或情感陪伴场景）关联到记忆配置
        if workspace.storage_type == 'neo4j':
            try:
                _create_default_memory_config(
                    db=db,
                    workspace_id=db_workspace.id,
                    workspace_name=db_workspace.name,
                    llm_id=llm,
                    embedding_id=embedding,
                    rerank_id=rerank,
                    scene_id=default_scene_id,  # 传入默认场景ID（优先教育场景，其次情感陪伴场景）
                    pruning_scene_name=default_scene_name,  # 传入场景名称作为语义剪枝场景值
                )
                business_logger.info(
                    f"为工作空间 {db_workspace.id} 创建默认记忆配置成功 (scene_id={default_scene_id})"
                )
            except Exception as mc_error:
                business_logger.error(
                    f"为工作空间 {db_workspace.id} 创建默认记忆配置失败: {str(mc_error)}"
                )
                # Don't fail workspace creation if memory config creation fails
                # The workspace can still function without a default memory config

        # 如果 storage_type 是 "rag"，自动创建知识库
        if workspace.storage_type == "rag":
            business_logger.info(
                f"检测到 storage_type 为 'rag'，开始为工作空间 "
                f"{db_workspace.id} 创建知识库"
            )
            try:
                from app.models.knowledge_model import KnowledgeType, PermissionType
                from app.repositories import knowledge_repository
                from app.schemas.knowledge_schema import KnowledgeCreate

                # 创建知识库数据
                knowledge_data = KnowledgeCreate(
                    workspace_id=db_workspace.id,
                    created_by=user.id,
                    parent_id=db_workspace.id,
                    name="USER_RAG_MERORY",
                    description=f"工作空间 {workspace.name} 的默认知识库",
                    avatar='',
                    type=KnowledgeType.General,
                    permission_id=PermissionType.Memory,
                    embedding_id=embedding,
                    reranker_id=rerank,
                    llm_id=llm,
                    image2text_id=llm,
                    parser_config={
                        "layout_recognize": "DeepDOC",
                        "chunk_token_num": 256,
                        "delimiter": "\n",
                        "auto_keywords": 0,
                        "auto_questions": 0,
                        "html4excel": False
                    }
                )

                # 直接使用 repository 创建知识库，避免 service 层的额外逻辑
                db_knowledge = knowledge_repository.create_knowledge(
                    db=db,
                    knowledge=knowledge_data
                )
                business_logger.info(
                    f"为工作空间 {db_workspace.id} 自动创建知识库成功: "
                    f"{db_knowledge.name} (ID: {db_knowledge.id})"
                )
            except Exception as kb_error:
                business_logger.error(
                    f"为工作空间 {db_workspace.id} 创建知识库失败: {str(kb_error)}"
                )
                db.rollback()
                raise BusinessException(
                    f"工作空间创建成功，但知识库创建失败: {str(kb_error)}",
                    BizCode.INTERNAL_ERROR
                )

        # 统一提交所有更改
        db.commit()
        business_logger.info(
            f"工作空间 {db_workspace.id} 及相关资源创建完成并已提交"
        )

        return db_workspace

    except Exception as e:
        business_logger.error(f"工作空间创建失败: {workspace.name} - {str(e)}")
        db.rollback()
        raise


def update_workspace(
        db: Session, workspace_id: uuid.UUID, workspace_in: WorkspaceUpdate, user: User
) -> Workspace:
    business_logger.info(f"更新工作空间: workspace_id={workspace_id}, 操作者: {user.username}")

    db_workspace = _check_workspace_admin_permission(db, workspace_id, user)
    try:
        # 更新工作空间
        business_logger.debug(f"执行工作空间更新: {db_workspace.name} (ID: {workspace_id})")
        update_data = workspace_in.model_dump(exclude_unset=True)
        for field, value in update_data.items():
            setattr(db_workspace, field, value)

        db.add(db_workspace)
        db.commit()
        db.refresh(db_workspace)
        business_logger.info(f"工作空间更新成功: {db_workspace.name} (ID: {workspace_id})")
        return db_workspace
    except Exception as e:
        business_logger.error(f"工作空间更新失败: workspace_id={workspace_id} - {str(e)}")
        db.rollback()
        raise


def get_workspace_members(
        db: Session, workspace_id: uuid.UUID, user: User
) -> List[WorkspaceMember]:
    """获取某工作空间的成员列表（关系序列化由模型关系支持）"""
    business_logger.info(f"获取工作空间成员: workspace_id={workspace_id}, 操作者: {user.username}")

    # 查找工作空间
    business_logger.debug(f"查找工作空间: {workspace_id}")
    workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not workspace:
        business_logger.warning(f"工作空间不存在: {workspace_id}")
        raise BusinessException(
            message="Workspace not found",
            code=BizCode.WORKSPACE_NOT_FOUND
        )

    # 权限检查：工作空间成员或超级管理员可以查看成员列表
    from app.core.permissions import Action, Resource, Subject, permission_service
    member = workspace_repository.get_member_in_workspace(
        db=db, user_id=user.id, workspace_id=workspace_id
    )
    workspace_memberships = {workspace_id} if member else set()

    subject = Subject.from_user(user, workspace_memberships=workspace_memberships)
    resource = Resource.from_workspace(workspace)

    try:
        permission_service.require_permission(
            subject,
            Action.READ,
            resource,
            error_message=f"用户 {user.username} 没有查看工作空间 {workspace_id} 成员列表的权限"
        )
    except PermissionDeniedException as e:
        business_logger.warning(
            f"权限不足: 用户 {user.username} 尝试获取工作空间 {workspace_id} 成员列表"
        )
        raise BusinessException(str(e), BizCode.WORKSPACE_ACCESS_DENIED)

    # 查询成员并预加载 user/workspace 关系
    members = workspace_repository.get_members_by_workspace(db=db, workspace_id=workspace_id)
    business_logger.info(f"工作空间成员数量: {len(members)} - workspace_id={workspace_id}")
    return members


# ==================== 邀请相关服务方法 ====================

def _generate_invite_token() -> tuple[str, str]:
    """生成邀请令牌和其哈希值

    Returns:
        tuple: (原始令牌, 令牌哈希)
    """
    # 生成32字节的随机令牌
    token = secrets.token_urlsafe(32)
    # 生成令牌的SHA256哈希
    token_hash = hashlib.sha256(token.encode()).hexdigest()
    return token, token_hash


def _check_workspace_member_permission(db: Session, workspace_id: uuid.UUID, user: User) -> Workspace | None:
    """检查用户是否为工作空间成员或超级管理员（使用统一权限服务）"""
    # 获取工作空间信息
    db_workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not db_workspace:
        raise BusinessException(
            message="Workspace not found",
            code=BizCode.WORKSPACE_NOT_FOUND
        )

    # 使用统一权限服务检查访问权限
    from app.core.permissions import Action, Resource, Subject, permission_service

    # 获取用户的工作空间成员关系
    member = workspace_repository.get_member_in_workspace(
        db=db, user_id=user.id, workspace_id=workspace_id
    )

    # 任何成员都有访问权限
    workspace_memberships = {workspace_id} if member else set()

    subject = Subject.from_user(user, workspace_memberships=workspace_memberships)
    resource = Resource.from_workspace(db_workspace)

    try:
        permission_service.require_permission(
            subject,
            Action.READ,
            resource,
            error_message=f"用户 {user.username} 不是工作空间 {workspace_id} 的成员"
        )
        business_logger.debug(f"用户 {user.username} 是工作空间 {workspace_id} 的成员或超级管理员")
    except PermissionDeniedException as e:
        business_logger.warning(f"权限不足: 用户 {user.username} 尝试访问工作空间 {workspace_id}")
        raise BusinessException(str(e), BizCode.WORKSPACE_NO_ACCESS)
    return db_workspace


def _check_workspace_admin_permission(db: Session, workspace_id: uuid.UUID, user: User) -> Workspace | None:
    """检查用户是否有工作空间管理员权限（使用统一权限服务）"""
    # 获取工作空间信息
    db_workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not db_workspace:
        raise BusinessException(
            message="Workspace not found",
            code=BizCode.WORKSPACE_NOT_FOUND
        )

    # 使用统一权限服务检查管理权限
    from app.core.permissions import Action, Resource, Subject, permission_service

    # 获取用户的工作空间成员关系
    member = workspace_repository.get_member_in_workspace(
        db=db, user_id=user.id, workspace_id=workspace_id
    )

    # 只有 manager 才有管理权限
    workspace_memberships = {workspace_id} if (member and member.role == WorkspaceRole.manager) else set()

    subject = Subject.from_user(user, workspace_memberships=workspace_memberships)
    resource = Resource.from_workspace(db_workspace)

    try:
        permission_service.require_permission(
            subject,
            Action.MANAGE,
            resource,
            error_message=f"用户 {user.username} 没有管理工作空间 {workspace_id} 的权限"
        )
        business_logger.debug(f"用户 {user.username} 有权限管理工作空间 {workspace_id}")
    except PermissionDeniedException as e:
        business_logger.warning(f"权限不足: 用户 {user.username} 尝试管理工作空间 {workspace_id}")
        raise BusinessException(str(e), BizCode.WORKSPACE_ACCESS_DENIED)
    return db_workspace


def create_workspace_invite(
        db: Session,
        workspace_id: uuid.UUID,
        invite_data: WorkspaceInviteCreate,
        user: User
) -> WorkspaceInviteResponse:
    """创建工作空间邀请"""
    business_logger.info(
        f"创建工作空间邀请: workspace_id={workspace_id}, email={invite_data.email}, 创建者: {user.username}")

    try:
        # 检查权限
        _check_workspace_admin_permission(db, workspace_id, user)
        if settings.ENABLE_SINGLE_WORKSPACE:
            # 检查被邀请用户是否已经在工作空间中
            from app.repositories import user_repository
            invited_user = user_repository.get_user_by_email(db, invite_data.email)

            if invited_user:
                # 用户存在，检查是否已经是工作空间成员
                existing_member = workspace_repository.get_member_in_workspace(
                    db=db,
                    user_id=invited_user.id,
                    workspace_id=workspace_id
                )
                if existing_member:
                    business_logger.warning(f"用户 {invite_data.email} 已经是工作空间成员")
                    raise BusinessException("该用户已经是工作空间成员", BizCode.RESOURCE_ALREADY_EXISTS)

        # 检查是否已有待处理的邀请
        invite_repo = WorkspaceInviteRepository(db)
        existing_invite = invite_repo.get_pending_invite_by_email_and_workspace(
            email=invite_data.email,
            workspace_id=workspace_id
        )

        invite_token = None
        if existing_invite:
            business_logger.info(f"邮箱 {invite_data.email} 在工作空间 {workspace_id} 已有待处理邀请，返回现有邀请")
            # 生成新的邀请链接（重新生成令牌）
            token, token_hash = _generate_invite_token()
            existing_invite.token_hash = token_hash
            existing_invite.updated_at = datetime.datetime.now()
            db.commit()
            db.refresh(existing_invite)
            invite_token = token
        else:
            # 生成邀请令牌
            token, token_hash = _generate_invite_token()
            # 创建邀请
            db_invite = invite_repo.create_invite(
                workspace_id=workspace_id,
                invite_data=invite_data,
                token_hash=token_hash,
                created_by_user_id=user.id
            )
            db.commit()
            db.refresh(db_invite)
            invite_token = token

        invite_obj = existing_invite or db_invite
        business_logger.info(f"工作空间邀请创建成功: invite_id={invite_obj.id}, email={invite_data.email}")

        # 构造响应
        response = WorkspaceInviteResponse.model_validate(invite_obj)
        response.invite_token = invite_token
        return response


    except Exception as e:
        db.rollback()
        business_logger.error(
            f"创建工作空间邀请失败: workspace_id={workspace_id}, email={invite_data.email} - {str(e)}")
        raise


def get_workspace_invites(
        db: Session,
        workspace_id: uuid.UUID,
        user: User,
        status: Optional[InviteStatus] = None,
        limit: int = 50,
        offset: int = 0
) -> List[WorkspaceInviteResponse]:
    """获取工作空间邀请列表"""
    business_logger.info(f"获取工作空间邀请列表: workspace_id={workspace_id}, 操作者: {user.username}")

    # 检查工作空间是否存在
    workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not workspace:
        raise BusinessException("工作空间不存在", BizCode.WORKSPACE_NOT_FOUND)

    # 检查权限
    _check_workspace_admin_permission(db, workspace_id, user)

    # 获取邀请列表
    invite_repo = WorkspaceInviteRepository(db)
    invites = invite_repo.get_workspace_invites(
        workspace_id=workspace_id,
        status=status,
        limit=limit,
        offset=offset
    )

    return [WorkspaceInviteResponse.model_validate(invite) for invite in invites]


def validate_invite_token(db: Session, token: str) -> InviteValidateResponse:
    """验证邀请令牌"""
    business_logger.info("验证邀请令牌")

    # 生成令牌哈希
    token_hash = hashlib.sha256(token.encode()).hexdigest()

    # 查找邀请
    invite_repo = WorkspaceInviteRepository(db)
    invite = invite_repo.get_invite_by_token_hash(token_hash)

    if not invite:
        business_logger.warning("邀请令牌无效")
        raise BusinessException("邀请令牌无效", BizCode.WORKSPACE_INVITE_NOT_FOUND)

    # 检查邀请状态和过期时间
    now = datetime.datetime.now()
    is_expired = invite.expires_at < now or invite.status != InviteStatus.pending
    is_valid = not is_expired

    # 获取工作空间信息
    workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=invite.workspace_id)

    business_logger.info(f"邀请令牌验证完成: valid={is_valid}, expired={is_expired}")

    return InviteValidateResponse(
        workspace_name=workspace.name,
        workspace_id=invite.workspace_id,
        email=invite.email,
        role=WorkspaceRole(invite.role),
        is_expired=is_expired,
        is_valid=is_valid
    )


def accept_workspace_invite(
        db: Session,
        accept_request: InviteAcceptRequest,
        user: User
) -> dict:
    """接受工作空间邀请"""
    business_logger.info(f"接受工作空间邀请: 用户 {user.username}")

    try:
        from app.core.config import settings

        # 生成令牌哈希
        token_hash = hashlib.sha256(accept_request.token.encode()).hexdigest()

        # 查找邀请
        invite_repo = WorkspaceInviteRepository(db)
        invite = invite_repo.get_invite_by_token_hash(token_hash)

        if not invite:
            business_logger.warning("邀请令牌无效")
            raise BusinessException("邀请令牌无效", BizCode.WORKSPACE_INVITE_NOT_FOUND)

        # 检查邀请状态
        if invite.status != InviteStatus.pending:
            business_logger.warning(f"邀请已被处理: status={invite.status}")
            raise BusinessException(f"邀请已被{invite.status}", BizCode.WORKSPACE_INVITE_INVALID)

        # 检查过期时间
        now = datetime.datetime.now()
        if invite.expires_at < now:
            business_logger.warning("邀请已过期")
            # 标记为过期
            invite_repo.update_invite_status(invite.id, InviteStatus.expired)
            raise BusinessException("邀请已过期", BizCode.WORKSPACE_INVITE_EXPIRED)

        # 检查邮箱是否匹配
        if invite.email != user.email:
            business_logger.warning(f"邮箱不匹配: invite_email={invite.email}, user_email={user.email}")
            raise BusinessException("邮箱与邀请邮箱不匹配", BizCode.FORBIDDEN)

        # 如果启用单工作空间模式，检查用户是否已有工作空间
        if settings.ENABLE_SINGLE_WORKSPACE:
            user_workspaces = workspace_repository.get_workspaces_by_user(db=db, user_id=user.id)
            if user_workspaces:
                business_logger.warning(f"单工作空间模式下用户已有工作空间: user={user.username}")
                raise BusinessException("用户只能加入一个工作空间", BizCode.FORBIDDEN)

        # 检查用户是否已经是工作空间成员
        existing_member = workspace_repository.get_member_in_workspace(
            db=db,
            user_id=user.id,
            workspace_id=invite.workspace_id
        )

        if existing_member:
            business_logger.info("用户已是工作空间成员，更新邀请状态")
            invite_repo.update_invite_status(
                invite.id,
                InviteStatus.accepted,
                accepted_at=now
            )
            db.commit()
            workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=invite.workspace_id)
            return {
                "message": "You are already a member of this workspace",
                "workspace": workspace
            }

        # 将角色映射到工作空间角色（现在直接使用相同的角色）
        workspace_role = invite.role

        # 添加用户到工作空间
        workspace_repository.add_member_to_workspace(
            db=db,
            user_id=user.id,
            workspace_id=invite.workspace_id,
            role=workspace_role
        )

        # 标记邀请为已接受
        invite_repo.update_invite_status(
            invite.id,
            InviteStatus.accepted,
            accepted_at=now
        )

        db.commit()

        # 获取工作空间信息
        workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=invite.workspace_id)

        business_logger.info(
            f"用户成功加入工作空间: user={user.username}, workspace={workspace.name}, role={workspace_role}")

        return {
            "message": "Successfully joined the workspace",
            "workspace": workspace,
            "role": workspace_role
        }

    except Exception as e:
        db.rollback()
        business_logger.error(f"接受工作空间邀请失败: user={user.username} - {str(e)}")
        raise


def revoke_workspace_invite(
        db: Session,
        workspace_id: uuid.UUID,
        invite_id: uuid.UUID,
        user: User
) -> dict:
    """撤销工作空间邀请"""
    business_logger.info(
        f"撤销工作空间邀请: workspace_id={workspace_id}, invite_id={invite_id}, 操作者: {user.username}")

    try:
        # 检查权限
        _check_workspace_admin_permission(db, workspace_id, user)

        # 撤销邀请
        invite_repo = WorkspaceInviteRepository(db)
        invite = invite_repo.revoke_invite(invite_id)

        if not invite:
            business_logger.warning(f"邀请不存在: invite_id={invite_id}")
            raise BusinessException("邀请不存在", BizCode.WORKSPACE_INVITE_NOT_FOUND)

        if invite.workspace_id != workspace_id:
            business_logger.warning(f"邀请不属于指定工作空间: invite_id={invite_id}, workspace_id={workspace_id}")
            raise BusinessException("邀请不属于指定工作空间", BizCode.BAD_REQUEST)

        db.commit()
        business_logger.info(f"工作空间邀请撤销成功: invite_id={invite_id}")
        return {"message": "邀请撤销成功"}

    except Exception as e:
        db.rollback()
        business_logger.error(f"撤销工作空间邀请失败: invite_id={invite_id} - {str(e)}")
        raise


def update_workspace_member_roles(
        db: Session,
        workspace_id: uuid.UUID,
        updates: List[WorkspaceMemberUpdate],
        user: User,
) -> List[WorkspaceMember]:
    """更新工作空间成员角色"""
    business_logger.info(
        f"更新工作空间成员角色: workspace_id={workspace_id}, 操作者: {user.username}, 更新数量: {len(updates)}")

    # 检查管理员权限
    _check_workspace_admin_permission(db, workspace_id, user)

    # 获取所有当前成员
    all_members = workspace_repository.get_members_by_workspace(db=db, workspace_id=workspace_id)
    member_map = {m.id: m for m in all_members}

    # 验证和业务规则检查
    update_ids = set()
    for upd in updates:
        # 检查成员是否存在
        if upd.id not in member_map:
            raise BusinessException(f"成员 {upd.id} 不存在于工作空间 {workspace_id}",
                                    BizCode.WORKSPACE_MEMBER_NOT_FOUND)

        member = member_map[upd.id]

        # 检查成员是否属于该工作空间
        if member.workspace_id != workspace_id:
            raise BusinessException(f"成员 {upd.id} 不属于工作空间 {workspace_id}", BizCode.WORKSPACE_MEMBER_NOT_FOUND)

        # 不能修改自己的角色
        if member.user_id == user.id:
            raise BusinessException("不能修改自己的角色", BizCode.BAD_REQUEST)

        update_ids.add(upd.id)

    # 检查是否至少保留一个 manager
    current_managers = [m for m in all_members if m.role == WorkspaceRole.manager]
    managers_after_update = [
        m for m in all_members
        if m.id not in update_ids and m.role == WorkspaceRole.manager
    ]

    # 添加更新后会成为 manager 的成员
    for upd in updates:
        if upd.role == WorkspaceRole.manager:
            managers_after_update.append(member_map[upd.id])

    if len(managers_after_update) == 0:
        raise BusinessException("工作空间至少需要一个管理员", BizCode.BAD_REQUEST)

    # 执行更新
    try:
        for upd in updates:
            workspace_repository.update_member_role_by_id(
                db=db,
                id=upd.id,
                role=upd.role,
            )
            business_logger.debug(f"更新成员 {upd.id} 角色为 {upd.role}")

        db.commit()

        # 重新获取更新后的成员列表
        updated_members = workspace_repository.get_members_by_workspace(db=db, workspace_id=workspace_id)
        business_logger.info(f"成员角色更新完成: workspace_id={workspace_id}, 更新数量={len(updates)}")

        return updated_members

    except Exception as e:
        db.rollback()
        business_logger.error(f"更新工作空间成员角色失败: workspace_id={workspace_id} - {str(e)}")
        raise BusinessException(f"更新成员角色失败: {str(e)}", BizCode.INTERNAL_ERROR)


def get_workspace_storage_type(
        db: Session,
        workspace_id: uuid.UUID,
        user: User,
) -> Optional[str]:
    """获取工作空间的存储类型

    Args:
        db: 数据库会话
        workspace_id: 工作空间ID
        user: 当前用户

    Returns:
        storage_type: 存储类型字符串，如果未设置则返回 None
    """
    business_logger.info(f"用户 {user.username} 请求获取工作空间 {workspace_id} 的存储类型")

    # 检查用户是否有权限访问该工作空间
    _check_workspace_member_permission(db, workspace_id, user)

    # 查询工作空间
    workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not workspace:
        business_logger.error(f"工作空间不存在: workspace_id={workspace_id}")
        raise BusinessException(
            code=BizCode.WORKSPACE_NOT_FOUND,
            message="工作空间不存在"
        )

    business_logger.info(f"成功获取工作空间 {workspace_id} 的存储类型: {workspace.storage_type}")
    return workspace.storage_type


def get_workspace_storage_type_without_auth(
        db: Session,
        workspace_id: uuid.UUID,
) -> Optional[str]:
    """获取工作空间的存储类型（无需权限验证，用于公开分享等场景）

    Args:
        db: 数据库会话
        workspace_id: 工作空间ID

    Returns:
        storage_type: 存储类型字符串，如果未设置则返回 None
    """
    business_logger.info(f"获取工作空间 {workspace_id} 的存储类型（无权限验证）")

    # 查询工作空间
    workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=workspace_id)
    if not workspace:
        business_logger.error(f"工作空间不存在: workspace_id={workspace_id}")
        raise BusinessException(
            code=BizCode.WORKSPACE_NOT_FOUND,
            message="工作空间不存在"
        )

    business_logger.info(f"成功获取工作空间 {workspace_id} 的存储类型: {workspace.storage_type}")
    return workspace.storage_type


def get_workspace_models_configs(
        db: Session,
        workspace_id: uuid.UUID,
        user: User,
) -> Optional[dict]:
    """获取工作空间的模型配置（llm, embedding, rerank）

    Args:
        db: 数据库会话
        workspace_id: 工作空间ID
        user: 当前用户

    Returns:
        dict: 包含 llm, embedding, rerank 的字典，如果工作空间不存在则返回 None
    """
    business_logger.info(f"用户 {user.username} 请求获取工作空间 {workspace_id} 的模型配置")

    # 检查用户是否有权限访问该工作空间
    _check_workspace_member_permission(db, workspace_id, user)

    # 查询工作空间模型配置
    configs = workspace_repository.get_workspace_models_configs(db=db, workspace_id=workspace_id)

    if configs is None:
        business_logger.error(f"工作空间不存在: workspace_id={workspace_id}")
        raise BusinessException(
            code=BizCode.WORKSPACE_NOT_FOUND,
            message="工作空间不存在"
        )

    business_logger.info(
        f"成功获取工作空间 {workspace_id} 的模型配置: "
        f"llm={configs.get('llm')}, embedding={configs.get('embedding')}, rerank={configs.get('rerank')}"
    )
    return configs


def update_workspace_models_configs(
        db: Session,
        workspace_id: uuid.UUID,
        models_update: WorkspaceModelsUpdate,
        user: User,
) -> Workspace:
    """更新工作空间的模型配置（llm, embedding, rerank）

    Args:
        db: 数据库会话
        workspace_id: 工作空间ID
        models_update: 模型配置更新对象
        user: 当前用户

    Returns:
        Workspace: 更新后的工作空间对象
    """
    business_logger.info(f"用户 {user.username} 请求更新工作空间 {workspace_id} 的模型配置")

    # 检查用户是否有管理员权限
    db_workspace = _check_workspace_admin_permission(db, workspace_id, user)

    try:
        if models_update.llm is not None:
            db_workspace.llm = str(models_update.llm) if models_update.llm else None
            business_logger.debug(f"更新LLM配置: {models_update.llm}")

        if models_update.embedding is not None:
            db_workspace.embedding = str(models_update.embedding) if models_update.embedding else None
            business_logger.debug(f"更新嵌入模型配置: {models_update.embedding}")

        if models_update.rerank is not None:
            db_workspace.rerank = str(models_update.rerank) if models_update.rerank else None
            business_logger.debug(f"更新重排序模型配置: {models_update.rerank}")

        db.add(db_workspace)
        db.commit()
        db.refresh(db_workspace)

        business_logger.info(
            f"工作空间模型配置更新成功: workspace_id={workspace_id}, "
            f"llm={db_workspace.llm}, embedding={db_workspace.embedding}, rerank={db_workspace.rerank}"
        )
        return db_workspace

    except Exception as e:
        business_logger.error(f"工作空间模型配置更新失败: workspace_id={workspace_id} - {str(e)}")
        db.rollback()
        raise BusinessException(f"更新模型配置失败: {str(e)}", BizCode.INTERNAL_ERROR)


def _fill_workspace_configs_model_defaults(
        db: Session,
        workspace: Workspace
) -> None:
    """Fill empty model fields for all memory configs in a workspace.
    
    Updates llm_id, embedding_id, rerank_id, reflection_model_id, and emotion_model_id
    if they are None, using the corresponding workspace default models.
    
    Args:
        db: Database session
        workspace: The workspace containing default model settings
    """
    from app.models.memory_config_model import MemoryConfig

    # Get all configs for this workspace
    configs = db.query(MemoryConfig).filter(
        MemoryConfig.workspace_id == workspace.id
    ).all()

    if not configs:
        return

    # Map of memory_config field -> workspace field
    model_field_mappings = [
        ("llm_id", "llm"),
        ("embedding_id", "embedding"),
        ("rerank_id", "rerank"),
        ("reflection_model_id", "llm"),  # reflection uses LLM
        ("emotion_model_id", "llm"),  # emotion uses LLM
    ]

    configs_updated = 0

    for memory_config in configs:
        updated_fields = []

        for config_field, workspace_field in model_field_mappings:
            config_value = getattr(memory_config, config_field, None)
            workspace_value = getattr(workspace, workspace_field, None)

            if not config_value and workspace_value:
                setattr(memory_config, config_field, workspace_value)
                updated_fields.append(config_field)

        if updated_fields:
            configs_updated += 1
            business_logger.debug(
                f"Updated memory config {memory_config.config_id} fields: {updated_fields}"
            )

    if configs_updated > 0:
        try:
            db.commit()
            business_logger.info(
                f"Updated {configs_updated} memory configs in workspace {workspace.id} with default models"
            )
        except Exception as e:
            db.rollback()
            business_logger.error(
                f"Failed to update memory configs in workspace {workspace.id}: {str(e)}"
            )


def _create_default_memory_config(
        db: Session,
        workspace_id: uuid.UUID,
        workspace_name: str,
        llm_id: Optional[uuid.UUID] = None,
        embedding_id: Optional[uuid.UUID] = None,
        rerank_id: Optional[uuid.UUID] = None,
        scene_id: Optional[uuid.UUID] = None,
        pruning_scene_name: Optional[str] = None,
) -> None:
    """Create a default memory config for a newly created workspace.
    
    Args:
        db: Database session
        workspace_id: The workspace ID
        workspace_name: The workspace name (used for config naming)
        llm_id: Optional LLM model ID
        embedding_id: Optional embedding model ID
        rerank_id: Optional rerank model ID
        scene_id: Optional ontology scene ID (默认关联教育场景)
        pruning_scene_name: Optional pruning scene name，取自 ontology_scene.scene_name
    """
    from app.models.memory_config_model import MemoryConfig

    config_id = uuid.uuid4()

    default_config = MemoryConfig(
        config_id=config_id,
        config_name=f"{workspace_name} 默认配置",
        config_desc="工作空间创建时自动生成的默认记忆配置",
        workspace_id=workspace_id,
        llm_id=str(llm_id) if llm_id else None,
        embedding_id=str(embedding_id) if embedding_id else None,
        rerank_id=str(rerank_id) if rerank_id else None,
        scene_id=scene_id,  # 关联本体场景ID（默认为"在线教育"场景）
        pruning_scene=pruning_scene_name,  # 语义剪枝场景直接使用 scene_name
        state=True,  # Active by default
        is_default=True,  # Mark as workspace default
    )

    db.add(default_config)
    db.flush()  # 使用 flush 而不是 commit，让调用者统一提交

    business_logger.info(
        "Created default memory config for workspace",
        extra={
            "workspace_id": str(workspace_id),
            "config_id": str(config_id),
            "config_name": default_config.config_name,
            "scene_id": str(scene_id) if scene_id else None,
        }
    )


# ==================== 检查配置相关服务 ====================

def _ensure_default_memory_config(db: Session, workspace: Workspace) -> None:
    """Ensure a workspace has a default memory config, creating one if missing.
    
    Also fills empty model fields for all configs in this workspace.
    
    Args:
        db: Database session
        workspace: The workspace to check
    """
    from app.models.memory_config_model import MemoryConfig

    # Check if default config exists for this workspace
    existing_default = db.query(MemoryConfig).filter(
        MemoryConfig.workspace_id == workspace.id,
        MemoryConfig.is_default == True
    ).first()

    if not existing_default:
        # No default config exists, create one
        business_logger.info(
            f"Workspace {workspace.id} missing default memory config, creating one"
        )

        # 尝试获取默认场景ID，优先教育场景，其次情感陪伴场景
        default_scene_id = None
        try:
            from app.repositories.ontology_scene_repository import OntologySceneRepository
            from app.config.default_ontology_config import (
                ONLINE_EDUCATION_SCENE,
                EMOTIONAL_COMPANION_SCENE,
                get_scene_name
            )

            scene_repo = OntologySceneRepository(db)
            # 尝试中文和英文场景名称
            for language in ["zh", "en"]:
                # 优先尝试教育场景
                education_scene_name = get_scene_name(ONLINE_EDUCATION_SCENE, language)
                education_scene = scene_repo.get_by_name(education_scene_name, workspace.id)
                if education_scene:
                    default_scene_id = education_scene.scene_id
                    business_logger.info(
                        f"找到教育场景用于默认记忆配置: scene_id={default_scene_id}, scene_name={education_scene_name}"
                    )
                    break

                # 如果教育场景不存在，尝试情感陪伴场景
                companion_scene_name = get_scene_name(EMOTIONAL_COMPANION_SCENE, language)
                companion_scene = scene_repo.get_by_name(companion_scene_name, workspace.id)
                if companion_scene:
                    default_scene_id = companion_scene.scene_id
                    business_logger.info(
                        f"教育场景不存在，找到情感陪伴场景用于默认记忆配置: scene_id={default_scene_id}, scene_name={companion_scene_name}"
                    )
                    break
        except Exception as scene_error:
            business_logger.warning(
                f"获取默认场景失败，将创建不关联场景的记忆配置: {str(scene_error)}"
            )

        try:
            _create_default_memory_config(
                db=db,
                workspace_id=workspace.id,
                workspace_name=workspace.name,
                llm_id=uuid.UUID(workspace.llm) if workspace.llm else None,
                embedding_id=uuid.UUID(workspace.embedding) if workspace.embedding else None,
                rerank_id=uuid.UUID(workspace.rerank) if workspace.rerank else None,
                scene_id=default_scene_id,  # 传入默认场景ID（优先教育场景，其次情感陪伴场景）
            )
        except Exception as e:
            business_logger.error(
                f"Failed to create default memory config for workspace {workspace.id}: {str(e)}"
            )

    # Fill empty model fields for ALL configs in this workspace
    _fill_workspace_configs_model_defaults(db, workspace)


def _ensure_default_ontology_scenes(db: Session, workspace: Workspace) -> None:
    """Ensure a workspace has default ontology scenes, creating them if missing.

    Checks whether any is_system_default scene exists for the workspace.
    If not, runs the DefaultOntologyInitializer to create them.

    Args:
        db: Database session
        workspace: The workspace to check
    """
    from app.models.ontology_scene import OntologyScene

    # 幂等检查：是否已存在系统默认场景
    existing = db.query(OntologyScene).filter(
        OntologyScene.workspace_id == workspace.id,
        OntologyScene.is_system_default.is_(True)
    ).first()

    if existing:
        return

    business_logger.info(
        f"Workspace {workspace.id} missing default ontology scenes, creating them"
    )

    try:
        initializer = DefaultOntologyInitializer(db)
        success, error_msg = initializer.initialize_default_scenes(
            workspace.id, language="zh"
        )
        if success:
            db.commit()
            business_logger.info(
                f"为工作空间 {workspace.id} 补建默认本体场景成功"
            )
        else:
            business_logger.warning(
                f"为工作空间 {workspace.id} 补建默认本体场景失败: {error_msg}"
            )
    except Exception as e:
        db.rollback()
        business_logger.error(
            f"为工作空间 {workspace.id} 补建默认本体场景异常: {str(e)}"
        )
