# -*- coding: utf-8 -*-
"""本体场景Repository层

本模块提供本体场景的数据访问层实现。

Classes:
    OntologySceneRepository: 本体场景数据访问类
"""

import logging
from typing import List, Optional
from uuid import UUID

from sqlalchemy.orm import Session, joinedload

from app.core.logging_config import get_db_logger
from app.models.ontology_scene import OntologyScene


logger = get_db_logger()


class OntologySceneRepository:
    """本体场景Repository
    
    提供本体场景的CRUD操作和权限检查。
    
    Attributes:
        db: SQLAlchemy数据库会话
    """
    
    def __init__(self, db: Session):
        """初始化Repository
        
        Args:
            db: SQLAlchemy数据库会话
        """
        self.db = db
    
    def create(self, scene_data: dict, workspace_id: UUID) -> OntologyScene:
        """创建本体场景
        
        Args:
            scene_data: 场景数据字典，包含scene_name和scene_description
            workspace_id: 所属工作空间ID
            
        Returns:
            OntologyScene: 创建的场景对象
            
        Raises:
            Exception: 数据库操作失败
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scene = repo.create(
            ...     {"scene_name": "医疗场景", "scene_description": "描述"},
            ...     workspace_id
            ... )
        """
        try:
            logger.info(
                f"Creating ontology scene - "
                f"name={scene_data.get('scene_name')}, "
                f"workspace_id={workspace_id}"
            )
            
            scene = OntologyScene(
                scene_name=scene_data.get("scene_name"),
                scene_description=scene_data.get("scene_description"),
                workspace_id=workspace_id
            )
            
            self.db.add(scene)
            self.db.flush()  # 获取ID但不提交
            
            logger.info(
                f"Ontology scene created successfully - "
                f"scene_id={scene.scene_id}"
            )
            
            return scene
            
        except Exception as e:
            logger.error(
                f"Failed to create ontology scene: {str(e)}",
                exc_info=True
            )
            raise
    
    def get_by_id(self, scene_id: UUID) -> Optional[OntologyScene]:
        """根据ID获取场景
        
        Args:
            scene_id: 场景ID
            
        Returns:
            Optional[OntologyScene]: 场景对象，不存在则返回None
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scene = repo.get_by_id(scene_id)
        """
        try:
            logger.debug(f"Getting ontology scene by ID: {scene_id}")
            
            scene = self.db.query(OntologyScene).filter(
                OntologyScene.scene_id == scene_id
            ).first()
            
            if scene:
                logger.debug(f"Ontology scene found: {scene_id}")
            else:
                logger.debug(f"Ontology scene not found: {scene_id}")
            
            return scene
            
        except Exception as e:
            logger.error(
                f"Failed to get ontology scene by ID: {str(e)}",
                exc_info=True
            )
            raise
    
    def get_by_name(self, scene_name: str, workspace_id: UUID) -> Optional[OntologyScene]:
        """根据场景名称和工作空间ID获取场景（精确匹配）
        
        Args:
            scene_name: 场景名称
            workspace_id: 工作空间ID
            
        Returns:
            Optional[OntologyScene]: 场景对象，不存在则返回None
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scene = repo.get_by_name("医疗场景", workspace_id)
        """
        try:
            logger.debug(
                f"Getting ontology scene by name - "
                f"scene_name={scene_name}, workspace_id={workspace_id}"
            )
            
            scene = self.db.query(OntologyScene).options(
                joinedload(OntologyScene.classes)
            ).filter(
                OntologyScene.scene_name == scene_name,
                OntologyScene.workspace_id == workspace_id
            ).first()
            
            if scene:
                logger.debug(f"Ontology scene found: {scene_name}")
            else:
                logger.debug(f"Ontology scene not found: {scene_name}")
            
            return scene
            
        except Exception as e:
            logger.error(
                f"Failed to get ontology scene by name: {str(e)}",
                exc_info=True
            )
            raise
    
    def search_by_name(self, keyword: str, workspace_id: UUID) -> List[OntologyScene]:
        """根据关键词模糊搜索场景
        
        使用 LIKE 进行模糊匹配，支持中文和英文。
        
        Args:
            keyword: 搜索关键词
            workspace_id: 工作空间ID
            
        Returns:
            List[OntologyScene]: 匹配的场景列表
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scenes = repo.search_by_name("医疗", workspace_id)
        """
        try:
            logger.debug(
                f"Searching ontology scenes by keyword - "
                f"keyword={keyword}, workspace_id={workspace_id}"
            )
            
            # 使用 ilike 进行不区分大小写的模糊匹配
            scenes = self.db.query(OntologyScene).options(
                joinedload(OntologyScene.classes)
            ).filter(
                OntologyScene.scene_name.ilike(f"%{keyword}%"),
                OntologyScene.workspace_id == workspace_id
            ).order_by(
                OntologyScene.updated_at.desc()
            ).all()
            
            logger.info(
                f"Found {len(scenes)} ontology scenes matching keyword '{keyword}' "
                f"in workspace {workspace_id}"
            )
            
            return scenes
            
        except Exception as e:
            logger.error(
                f"Failed to search ontology scenes by keyword: {str(e)}",
                exc_info=True
            )
            raise
    
    def get_by_workspace(self, workspace_id: UUID, page: Optional[int] = None, page_size: Optional[int] = None) -> tuple:
        """获取工作空间下的所有场景（支持分页）
        
        使用joinedload预加载classes关系以统计数量。
        
        Args:
            workspace_id: 工作空间ID
            page: 页码（可选，从1开始）
            page_size: 每页数量（可选）
            
        Returns:
            tuple: (场景列表, 总数量)
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scenes, total = repo.get_by_workspace(workspace_id)
            >>> scenes, total = repo.get_by_workspace(workspace_id, page=1, page_size=10)
        """
        try:
            logger.debug(f"Getting ontology scenes by workspace: {workspace_id}, page={page}, page_size={page_size}")
            
            # 构建基础查询
            query = self.db.query(OntologyScene).options(
                joinedload(OntologyScene.classes)
            ).filter(
                OntologyScene.workspace_id == workspace_id
            ).order_by(
                OntologyScene.updated_at.desc()
            )
            
            # 获取总数
            total = query.count()
            
            # 如果提供了分页参数，应用分页
            if page is not None and page_size is not None:
                offset = (page - 1) * page_size
                query = query.offset(offset).limit(page_size)
                logger.debug(f"Applying pagination: offset={offset}, limit={page_size}")
            
            scenes = query.all()
            
            logger.info(
                f"Found {len(scenes)} ontology scenes (total: {total}) in workspace {workspace_id}"
            )
            
            return scenes, total
            
        except Exception as e:
            logger.error(
                f"Failed to get ontology scenes by workspace: {str(e)}",
                exc_info=True
            )
            raise
    
    def update(self, scene_id: UUID, update_data: dict) -> Optional[OntologyScene]:
        """更新场景信息
        
        Args:
            scene_id: 场景ID
            update_data: 更新数据字典
            
        Returns:
            Optional[OntologyScene]: 更新后的场景对象，不存在则返回None
            
        Raises:
            Exception: 数据库操作失败
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scene = repo.update(
            ...     scene_id,
            ...     {"scene_name": "新名称"}
            ... )
        """
        try:
            logger.info(f"Updating ontology scene: {scene_id}")
            
            scene = self.get_by_id(scene_id)
            if not scene:
                logger.warning(f"Ontology scene not found for update: {scene_id}")
                return None
            
            # 更新字段
            if "scene_name" in update_data and update_data["scene_name"] is not None:
                scene.scene_name = update_data["scene_name"]
            
            if "scene_description" in update_data:
                scene.scene_description = update_data["scene_description"]
            
            self.db.flush()
            
            logger.info(f"Ontology scene updated successfully: {scene_id}")
            
            return scene
            
        except Exception as e:
            logger.error(
                f"Failed to update ontology scene: {str(e)}",
                exc_info=True
            )
            raise
    
    def delete(self, scene_id: UUID) -> bool:
        """删除场景（级联删除类型）
        
        依赖数据库级联删除配置（ondelete="CASCADE"）。
        
        Args:
            scene_id: 场景ID
            
        Returns:
            bool: 删除成功返回True，场景不存在返回False
            
        Raises:
            Exception: 数据库操作失败
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> success = repo.delete(scene_id)
        """
        try:
            logger.info(f"Deleting ontology scene: {scene_id}")
            
            scene = self.get_by_id(scene_id)
            if not scene:
                logger.warning(f"Ontology scene not found for delete: {scene_id}")
                return False
            
            self.db.delete(scene)
            self.db.flush()
            
            logger.info(
                f"Ontology scene deleted successfully (cascade): {scene_id}"
            )
            
            return True
            
        except Exception as e:
            logger.error(
                f"Failed to delete ontology scene: {str(e)}",
                exc_info=True
            )
            raise
    
    def check_ownership(self, scene_id: UUID, workspace_id: UUID) -> bool:
        """检查场景是否属于指定工作空间
        
        Args:
            scene_id: 场景ID
            workspace_id: 工作空间ID
            
        Returns:
            bool: 属于返回True，否则返回False
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> is_owner = repo.check_ownership(scene_id, workspace_id)
        """
        try:
            logger.debug(
                f"Checking scene ownership - "
                f"scene_id={scene_id}, workspace_id={workspace_id}"
            )
            
            count = self.db.query(OntologyScene).filter(
                OntologyScene.scene_id == scene_id,
                (OntologyScene.workspace_id == workspace_id) | (OntologyScene.is_system_default == True)
            ).count()
            
            is_owner = count > 0
            
            logger.debug(
                f"Scene ownership check result: {is_owner} - "
                f"scene_id={scene_id}"
            )
            
            return is_owner
            
        except Exception as e:
            logger.error(
                f"Failed to check scene ownership: {str(e)}",
                exc_info=True
            )
            raise

    def get_simple_list(self, workspace_id: UUID) -> List[dict]:
        """获取场景简单列表（仅包含scene_id和scene_name，用于下拉选择）
        
        这是一个轻量级查询，不加载关联的classes，响应速度快。
        
        Args:
            workspace_id: 工作空间ID
            
        Returns:
            List[dict]: 场景简单列表，每项包含scene_id和scene_name
            
        Examples:
            >>> repo = OntologySceneRepository(db)
            >>> scenes = repo.get_simple_list(workspace_id)
            >>> # [{"scene_id": "xxx", "scene_name": "场景1"}, ...]
        """
        try:
            logger.debug(f"Getting simple scene list for workspace: {workspace_id}")
            
            # 只查询需要的字段，不加载关联数据
            results = self.db.query(
                OntologyScene.scene_id,
                OntologyScene.scene_name
            ).filter(
                OntologyScene.workspace_id == workspace_id
            ).order_by(
                OntologyScene.updated_at.desc()
            ).all()
            
            scenes = [
                {"scene_id": str(r.scene_id), "scene_name": r.scene_name}
                for r in results
            ]
            
            logger.info(f"Found {len(scenes)} scenes (simple list) in workspace {workspace_id}")
            
            return scenes
            
        except Exception as e:
            logger.error(
                f"Failed to get simple scene list: {str(e)}",
                exc_info=True
            )
            raise
