#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
VWED库位相关内置模块
提供在线脚本中库位操作相关功能
"""

import json
from typing import Any, Dict
from sqlalchemy import and_, select

from utils.logger import get_logger
from utils.json_parser import safe_parse_dict
from data.session import get_async_session
from data.models.operate_point import OperatePoint
from data.models.operate_point_layer import OperatePointLayer
from data.models.storage_area import StorageArea

logger = get_logger("services.online_script.location_module")


class VWEDLocationModule:
    """VWED库位模块"""
    
    def __init__(self, script_id: str):
        self.script_id = script_id
        logger.debug(f"初始化库位模块，脚本ID: {script_id}")
    
    async def is_point_exist(self, point_name: str) -> bool:
        """
        检查站点是否存在
        
        Args:
            point_name: 站点名
            
        Returns:
            bool: True表示站点存在，False表示不存在
        """
        try:
            async with get_async_session() as db:
                result = await db.execute(
                    select(OperatePoint).filter(
                        OperatePoint.station_name == point_name,
                        OperatePoint.is_deleted == False
                    )
                )
                point = result.scalars().first()
                return point is not None
                
        except Exception as e:
            logger.error(f"检查站点是否存在失败: {str(e)}")
            raise
    
    async def check_site_existed_by_site_id(self, site_id: str) -> bool:
        """
        检查库位是否存在
        
        Args:
            site_id: 库位名称
            
        Returns:
            bool: True表示库位存在，False表示不存在
        """
        try:
            async with get_async_session() as db:
                result = await db.execute(
                    select(OperatePointLayer).filter(
                        OperatePointLayer.layer_name == site_id,
                        OperatePointLayer.is_deleted == False
                    )
                )
                layer = result.scalars().first()
                return layer is not None
                
        except Exception as e:
            logger.error(f"检查库位是否存在失败: {str(e)}")
            raise
    
    async def check_site_group_existed_by_group_name(self, group_name: str) -> bool:
        """
        检查库区是否存在
        
        Args:
            group_name: 库区名称
            
        Returns:
            bool: True表示库区存在，False表示不存在
        """
        try:
            async with get_async_session() as db:
                result = await db.execute(
                    select(StorageArea).filter(
                        StorageArea.area_name == group_name,
                        StorageArea.is_deleted == False
                    )
                )
                area = result.scalars().first()
                return area is not None
                
        except Exception as e:
            logger.error(f"检查库区是否存在失败: {str(e)}")
            raise
    
    def _build_field_conditions(self, field_attr, field_values):
        """构建单个字段的查询条件，支持列表AND逻辑和模糊匹配"""
        if not isinstance(field_values, list):
            field_values = [field_values]
        
        and_conditions = []
        for value in field_values:
            if isinstance(value, str) and value.startswith("'") and value.endswith("'") and "%" in value:
                # 模糊查询：'%pattern%' 格式
                pattern = value.strip("'")
                and_conditions.append(field_attr.like(pattern))
            else:
                # 精确匹配
                and_conditions.append(field_attr == value)
        
        # 使用AND逻辑连接所有条件
        if len(and_conditions) == 1:
            return and_conditions[0]
        else:
            return and_(*and_conditions)

    def _build_query_filters(self, conditions: Dict[str, Any]):
        """构建查询过滤条件"""
        query = select(OperatePointLayer).filter(OperatePointLayer.is_deleted == False)
        
        # 字段映射配置
        field_mappings = {
            "site_ids": OperatePointLayer.layer_name,
            "area": OperatePointLayer.area_name,
            "group_names": OperatePointLayer.area_name,
            "content": OperatePointLayer.goods_content,
            "tags": OperatePointLayer.tags,
            "no": OperatePointLayer.layer_name,
            "type": OperatePointLayer.location_type,
            "locked_by": OperatePointLayer.locked_by,
        }
        
        # 处理字段映射的条件
        for field_name, field_attr in field_mappings.items():
            if field_name in conditions:
                condition = self._build_field_conditions(field_attr, conditions[field_name])
                query = query.filter(condition)
        
        # 处理布尔字段
        if "filled" in conditions:
            filled = conditions["filled"]
            if isinstance(filled, bool):
                query = query.filter(OperatePointLayer.is_occupied == filled)
            elif isinstance(filled, list):
                # 如果是列表，使用AND逻辑（虽然布尔字段用列表不太常见）
                bool_conditions = []
                for val in filled:
                    if isinstance(val, bool):
                        bool_conditions.append(OperatePointLayer.is_occupied == val)
                if bool_conditions:
                    query = query.filter(and_(*bool_conditions))

        if "locked" in conditions:
            locked = conditions["locked"]
            if isinstance(locked, bool):
                query = query.filter(OperatePointLayer.is_locked == locked)
            elif isinstance(locked, list):
                bool_conditions = []
                for val in locked:
                    if isinstance(val, bool):
                        bool_conditions.append(OperatePointLayer.is_locked == val)
                if bool_conditions:
                    query = query.filter(and_(*bool_conditions))

        return query
    
    async def find_sites_by_condition(self, conditions: str, sort: str) -> str:
        """
        根据条件获取库位
        
        Args:
            conditions: 查询条件JSON字符串
            sort: 排序方式，"ASC"升序，"DESC"降序
            
        Returns:
            str: 库位列表JSON字符串，如果没有找到则返回"null"
        """
        try:
            condition_dict = safe_parse_dict(conditions, self.script_id)
            if condition_dict is None:
                return "null"
            
            async with get_async_session() as db:
                query = self._build_query_filters(condition_dict)
                # 排序
                if sort.upper() == "DESC":
                    query = query.order_by(OperatePointLayer.layer_name.desc())
                else:
                    query = query.order_by(OperatePointLayer.layer_name.asc())
                
                result = await db.execute(query)
                results = result.scalars().all()
                
                if not results:
                    return "null"
                
                # 转换为返回格式
                site_list = []
                for site in results:
                    site_data = {
                        "area": site.area_name or "",
                        "content": site.goods_content or "",
                        "depth": "",    # 需要根据实际需求映射
                        "disabled": site.is_disabled,
                        "filled": 1 if site.is_occupied else 0,
                        "group_names": site.area_name or "",
                        "level": "",    # 需要根据实际需求映射
                        "locked": 1 if site.is_locked else 0,
                        "locked_by": site.locked_by or "",
                        "no": site.layer_name or "",
                        "preparing": False,  # 需要根据实际业务逻辑确定
                        "row_num": "",       # 需要根据实际需求映射
                        "site_id": site.layer_name or "",
                        "tags": site.tags or "",
                        "type": site.location_type,
                        "working": False     # 需要根据实际业务逻辑确定
                    }
                    site_list.append(site_data)
                
                return json.dumps(site_list, ensure_ascii=False)
                
        except Exception as e:
            logger.error(f"根据条件获取库位失败: {str(e)}")
            raise
    
    async def find_available_sites_by_condition(self, conditions: str, sort: str) -> str:
        """
        根据条件获取有效库位（未禁用且同步成功的库位）
        
        Args:
            conditions: 查询条件JSON字符串
            sort: 排序方式，"ASC"升序，"DESC"降序
            
        Returns:
            str: 库位列表JSON字符串，如果没有找到则返回"null"
        """
        try:
            condition_dict = safe_parse_dict(conditions, self.script_id)
            if condition_dict is None:
                return "null"
            
            async with get_async_session() as db:
                query = self._build_query_filters(condition_dict)
                
                # 添加有效库位的过滤条件：未禁用且同步成功
                query = query.filter(
                    OperatePointLayer.is_disabled == False
                    # 这里假设sync_failed字段存在，如果不存在可以去掉这个条件
                    # OperatePointLayer.sync_failed == False
                )
                
                # 排序
                if sort.upper() == "DESC":
                    query = query.order_by(OperatePointLayer.layer_name.desc())
                else:
                    query = query.order_by(OperatePointLayer.layer_name.asc())
                
                result = await db.execute(query)
                results = result.scalars().all()
                
                if not results:
                    return "null"
                
                # 转换为返回格式
                site_list = []
                for site in results:
                    site_data = {
                        "area": site.area_name or "",
                        "content": site.goods_content or "",
                        "depth": "",
                        "disabled": site.is_disabled,
                        "filled": 1 if site.is_occupied else 0,
                        "group_names": site.area_name or "",
                        "level": "",
                        "locked": 1 if site.is_locked else 0,
                        "locked_by": site.locked_by or "",
                        "no": site.layer_name or "",
                        "preparing": False,
                        "row_num": "",
                        "site_id": site.layer_name or "",
                        "tags": site.tags or "",
                        "type": site.location_type,
                        "working": False
                    }
                    site_list.append(site_data)
                
                return json.dumps(site_list, ensure_ascii=False)
                
        except Exception as e:
            logger.error(f"根据条件获取有效库位失败: {str(e)}")
            raise
    
    async def find_available_sites_by_ext_fields(self, conditions: str) -> str:
        """
        根据扩展字段获取有效库位
        
        Args:
            conditions: 查询条件JSON字符串，包含扩展字段条件
            
        Returns:
            str: 库位列表JSON字符串，如果没有找到则返回"null"
        """
        try:
            from utils.json_parser import safe_parse_list
            condition_list = safe_parse_list(conditions, self.script_id)
            if condition_list is None:
                return "null"
            
            async with get_async_session() as db:
                query = select(OperatePointLayer).filter(
                    OperatePointLayer.is_deleted == False,
                    OperatePointLayer.is_disabled == False
                )
                
                # 处理扩展字段条件
                from sqlalchemy import text
                for i, condition in enumerate(condition_list):
                    attr_name = condition.get("attribute_name")
                    attr_value = condition.get("attribute_value")
                    
                    # 处理字段名，确保JSON路径正确
                    # 如果字段名是纯数字或包含特殊字符，需要用引号包围
                    if attr_name.isdigit() or not attr_name.isidentifier():
                        json_path = f'$.extended_fields."{attr_name}".value'
                    else:
                        json_path = f"$.extended_fields.{attr_name}.value"
                    
                    
                    if isinstance(attr_value, str) and "%" in attr_value:
                        # 模糊查询 - 使用JSON_UNQUOTE去除JSON字符串的引号
                        param_name = f"pattern_{i}"
                        sql_condition = f"JSON_UNQUOTE(JSON_EXTRACT(config_json, '{json_path}')) LIKE :{param_name}"
                        query = query.filter(text(sql_condition).params(**{param_name: attr_value}))
                    else:
                        # 精确查询
                        param_name = f"value_{i}"
                        sql_condition = f"JSON_EXTRACT(config_json, '{json_path}') = :{param_name}"
                        query = query.filter(text(sql_condition).params(**{param_name: attr_value}))
                
                result = await db.execute(query)
                results = result.scalars().all()
                
                if not results:
                    return "null"
                
                # 转换为返回格式
                site_list = []
                for site in results:
                    site_data = {
                        "area": site.area_name,
                        "content": site.goods_content,
                        "filled": 1 if site.is_occupied else 0,
                        "group_name": site.area_name,
                        "locked": 1 if site.is_locked else 0,
                        "locked_by": site.locked_by,
                        "site_id": site.layer_name,
                        "site_name": site.layer_name,
                        "tags": site.tags,
                        "type": site.location_type
                    }
                    site_list.append(site_data)
                
                return json.dumps(site_list, ensure_ascii=False)
                
        except Exception as e:
            logger.error(f"根据扩展字段获取有效库位失败: {str(e)}")
            raise
    
    async def update_sites_by_condition(self, conditions: str, values: str) -> int:
        """
        根据条件更新库位
        
        Args:
            conditions: 更新条件JSON字符串
            values: 修改的字段JSON字符串
            
        Returns:
            int: 更新成功的数据库记录行数
        """
        try:
            condition_dict = safe_parse_dict(conditions, self.script_id)
            value_dict = safe_parse_dict(values, self.script_id)
            
            if condition_dict is None or value_dict is None:
                return 0
            
            async with get_async_session() as db:
                from sqlalchemy import update
                
                # 构建更新字段
                update_data = {}
                
                # 映射字段名
                field_mapping = {
                    "area": "area_name",
                    "content": "goods_content",
                    "disabled": "is_disabled",
                    "filled": "is_occupied",
                    "group_name": "area_name",
                    "locked": "is_locked",
                    "locked_by": "locked_by",
                    "site_id": "layer_name",
                    "tags": "tags",
                    "type": "location_type",
                    "preparing": None,  # 暂时不支持
                    "working": None,    # 暂时不支持
                }
                
                for key, value in value_dict.items():
                    if key in field_mapping and field_mapping[key] is not None:
                        update_data[field_mapping[key]] = value
                
                if not update_data:
                    return 0
                
                # 检查是否需要更新库区名称，如果是则需要同步相关表
                area_name_update = update_data.get("area_name")
                if area_name_update:
                    # 先获取旧的库区名称，用于同步相关表
                    query_old_areas = self._build_query_filters(condition_dict)
                    result = await db.execute(query_old_areas)
                    affected_sites = result.scalars().all()
                    
                    old_area_names = set()
                    for site in affected_sites:
                        if site.area_name:
                            old_area_names.add(site.area_name)
                
                # 构建更新查询
                filtered_query = self._build_query_filters(condition_dict)
                
                # 执行OperatePointLayer表的更新
                stmt = update(OperatePointLayer).values(**update_data)
                
                # 应用同样的过滤条件
                for condition in filtered_query.whereclause.clauses if hasattr(filtered_query.whereclause, 'clauses') else [filtered_query.whereclause]:
                    stmt = stmt.where(condition)
                
                result = await db.execute(stmt)
                affected_rows = result.rowcount
                
                # 如果修改了库区名称，需要同步相关表
                if area_name_update and old_area_names:
                    logger.debug(f"同步库区名称更新: {old_area_names} -> {area_name_update}")
                    
                    # 更新 OperatePoint 表中的 area_name
                    from data.models.operate_point import OperatePoint
                    for old_area_name in old_area_names:
                        await db.execute(
                            update(OperatePoint)
                            .where(
                                and_(
                                    OperatePoint.area_name == old_area_name,
                                    OperatePoint.is_deleted == False
                                )
                            )
                            .values(area_name=area_name_update)
                        )
                    
                    # 更新 StorageArea 表中的 area_name  
                    from data.models.storage_area import StorageArea
                    for old_area_name in old_area_names:
                        await db.execute(
                            update(StorageArea)
                            .where(
                                and_(
                                    StorageArea.area_name == old_area_name,
                                    StorageArea.is_deleted == False
                                )
                            )
                            .values(area_name=area_name_update)
                        )
                
                await db.commit()
                return affected_rows
                
        except Exception as e:
            logger.error(f"根据条件更新库位失败: {str(e)}")
            raise
    
    async def update_site_ext_field_by_id_and_ext_field_name(self, conditions: str) -> None:
        """
        根据条件更新库位扩展字段值
        
        Args:
            conditions: 库位ID、扩展字段名和更新值的JSON字符串
        """
        try:
            from utils.json_parser import safe_parse_list
            condition_list = safe_parse_list(conditions, self.script_id)
            if condition_list is None:
                return
            
            async with get_async_session() as db:
                 for condition in condition_list:
                    site_id = condition.get("site_id")
                    ext_field_name = condition.get("ext_field_name")
                    update_value = condition.get("update_value")
                    
                    if not site_id or not ext_field_name:
                        continue
                    
                    # 查询库位
                    result = await db.execute(
                        select(OperatePointLayer).filter(
                            OperatePointLayer.layer_name == site_id,
                            OperatePointLayer.is_deleted == False
                        )
                    )
                    site = result.scalars().first()
                    
                    if site:
                        # 解析现有的config_json
                        config_data = {}
                        if site.config_json:
                            try:
                                config_data = json.loads(site.config_json)
                            except:
                                config_data = {}
                        
                        # 更新扩展字段
                        if "extended_fields" not in config_data:
                            config_data["extended_fields"] = {}
                        
                        config_data["extended_fields"][ext_field_name] = update_value
                        
                        # 保存更新后的config_json
                        site.config_json = json.dumps(config_data, ensure_ascii=False)
                
        except Exception as e:
            logger.error(f"根据条件更新库位扩展字段值失败: {str(e)}")
            raise


__all__ = ['VWEDLocationModule']