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

"""
OPC UA 模拟服务器
用于测试在线脚本中的OPC UA通信功能
"""

import time
import threading
import logging
from typing import Dict, Any
from opcua import Server, ua

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class OpcUaTestServer:
    """OPC UA 测试服务器"""
    
    def __init__(self, host='localhost', port=4840):
        self.host = host
        self.port = port
        self.endpoint = f"opc.tcp://{host}:{port}/freeopcua/server/"
        self.server = None
        self.server_thread = None
        self.update_thread = None
        self.running = False
        self.nodes: Dict[str, Any] = {}
        
        # 初始化服务器
        self._setup_server()
        
    def _setup_server(self):
        """设置OPC UA服务器"""
        self.server = Server()
        self.server.set_endpoint(self.endpoint)
        
        # 设置服务器名称和应用URI
        self.server.set_server_name("VWED OPC UA Test Server")
        
        # 设置安全策略
        self.server.set_security_policy([
            ua.SecurityPolicyType.NoSecurity,
            ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
            ua.SecurityPolicyType.Basic256Sha256_Sign
        ])
        
        # 创建命名空间
        uri = "http://vwed.test.opcua.server"
        self.namespace_idx = self.server.register_namespace(uri)
        
        # 获取根节点
        root = self.server.get_root_node()
        
        # 创建对象节点
        myobj = root.add_object(self.namespace_idx, "VWEDTestObject")
        
        # 创建各种类型的变量节点用于测试
        self._create_test_variables(myobj)
        
    def _create_test_variables(self, parent_node):
        """创建测试变量节点"""
        
        # 1. 基本数据类型变量
        self.nodes['boolean_var'] = parent_node.add_variable(
            self.namespace_idx, "BooleanVariable", True
        )
        self.nodes['boolean_var'].set_writable()
        
        self.nodes['int_var'] = parent_node.add_variable(
            self.namespace_idx, "IntegerVariable", 42
        )
        self.nodes['int_var'].set_writable()
        
        self.nodes['float_var'] = parent_node.add_variable(
            self.namespace_idx, "FloatVariable", 3.14159
        )
        self.nodes['float_var'].set_writable()
        
        self.nodes['string_var'] = parent_node.add_variable(
            self.namespace_idx, "StringVariable", "Hello VWED"
        )
        self.nodes['string_var'].set_writable()
        
        # 2. 动态变化的变量（模拟传感器数据）
        self.nodes['temperature'] = parent_node.add_variable(
            self.namespace_idx, "Temperature", 25.0
        )
        self.nodes['temperature'].set_writable()
        
        self.nodes['pressure'] = parent_node.add_variable(
            self.namespace_idx, "Pressure", 101.3
        )
        self.nodes['pressure'].set_writable()
        
        self.nodes['counter'] = parent_node.add_variable(
            self.namespace_idx, "Counter", 0
        )
        self.nodes['counter'].set_writable()
        
        # 3. 只读变量
        self.nodes['readonly_var'] = parent_node.add_variable(
            self.namespace_idx, "ReadOnlyVariable", "Read Only Value"
        )
        # 不设置writable，默认为只读
        
        # 4. 数组变量
        self.nodes['array_var'] = parent_node.add_variable(
            self.namespace_idx, "ArrayVariable", [1, 2, 3, 4, 5]
        )
        self.nodes['array_var'].set_writable()
        
        # 5. 创建不同NodeId类型的节点进行测试
        
        # 字符串NodeId: s=StringNodeId
        self.nodes['string_node'] = parent_node.add_variable(
            ua.NodeId("StringNodeId", self.namespace_idx), "StringNodeVariable", "String Node Value"
        )
        self.nodes['string_node'].set_writable()
        
        # 整数NodeId: i=1001
        self.nodes['int_node'] = parent_node.add_variable(
            ua.NodeId(1001, self.namespace_idx), "IntNodeVariable", 1001
        )
        self.nodes['int_node'].set_writable()
        
        # GUID NodeId
        import uuid
        guid = uuid.UUID('550e8400-e29b-41d4-a716-446655440000')
        self.nodes['guid_node'] = parent_node.add_variable(
            ua.NodeId(guid, self.namespace_idx), "GuidNodeVariable", "GUID Node Value"
        )
        self.nodes['guid_node'].set_writable()
        
        # 字节NodeId
        byte_id = b'ByteNodeId'
        self.nodes['byte_node'] = parent_node.add_variable(
            ua.NodeId(byte_id, self.namespace_idx), "ByteNodeVariable", "Byte Node Value"
        )
        self.nodes['byte_node'].set_writable()
        
        logger.info("创建测试变量节点完成")
        
    def start_server(self):
        """启动OPC UA服务器"""
        if self.running:
            logger.warning("服务器已经在运行")
            return
            
        logger.info(f"启动OPC UA服务器: {self.endpoint}")
        
        try:
            self.server.start()
            self.running = True
            
            # 启动数据更新线程
            self.update_thread = threading.Thread(target=self._update_data_loop, daemon=True)
            self.update_thread.start()
            
            logger.info("OPC UA服务器启动成功")
            
        except Exception as e:
            logger.error(f"启动OPC UA服务器失败: {e}")
            raise
            
    def _update_data_loop(self):
        """更新测试数据的循环"""
        counter = 0
        while self.running:
            try:
                # 更新计数器
                self.nodes['counter'].set_value(counter)
                
                # 更新温度（模拟传感器数据，20-30度之间波动）
                import math
                temperature = 25.0 + 5.0 * math.sin(counter * 0.1)
                self.nodes['temperature'].set_value(temperature)
                
                # 更新压力（模拟传感器数据，100-102之间波动）
                pressure = 101.0 + math.cos(counter * 0.05)
                self.nodes['pressure'].set_value(pressure)
                
                # 更新布尔值（每5秒切换一次）
                boolean_value = (counter // 5) % 2 == 0
                self.nodes['boolean_var'].set_value(boolean_value)
                
                # 更新数组（循环移位）
                current_array = self.nodes['array_var'].get_value()
                if isinstance(current_array, list) and len(current_array) > 0:
                    # 循环移位
                    new_array = current_array[1:] + [current_array[0] + counter]
                    self.nodes['array_var'].set_value(new_array)
                
                counter += 1
                time.sleep(1)  # 每秒更新一次
                
            except Exception as e:
                logger.error(f"数据更新错误: {e}")
                time.sleep(1)
                
    def stop_server(self):
        """停止服务器"""
        logger.info("正在停止OPC UA服务器...")
        self.running = False
        
        if self.server:
            try:
                self.server.stop()
                logger.info("OPC UA服务器已停止")
            except Exception as e:
                logger.error(f"停止服务器时出错: {e}")
                
    def get_server_info(self):
        """获取服务器信息"""
        return {
            'host': self.host,
            'port': self.port,
            'endpoint': self.endpoint,
            'running': self.running,
            'namespace_index': self.namespace_idx,
            'test_nodes': list(self.nodes.keys()),
        }
        
    def get_node_info(self):
        """获取节点信息（用于测试参考）"""
        if not self.running:
            return None
            
        node_info = {}
        try:
            for name, node in self.nodes.items():
                node_id = node.nodeid
                print("node_id::::", node_id)
                # node
                value = node.get_value()
                
                # 解析NodeId类型
                node_id_str = ""
                identifier = node_id.identifier
                if isinstance(identifier, int):
                    node_id_str = f"i={identifier}"
                elif isinstance(identifier, str):
                    node_id_str = f"s={identifier}"
                elif hasattr(identifier, 'hex'):  # UUID
                    node_id_str = f"g={identifier}"
                elif isinstance(identifier, bytes):
                    import base64
                    node_id_str = f"b={base64.b64encode(identifier).decode()}"
                else:
                    node_id_str = f"i={identifier}"
                
                node_info[name] = {
                    'node_id': node_id_str,
                    'namespace_index': node_id.namespace_index,
                    'value': value,
                    'data_type': type(value).__name__
                }
                
        except Exception as e:
            logger.error(f"获取节点信息失败: {e}")
            
        return node_info
        
    def set_node_value(self, node_name: str, value: Any):
        """设置节点值（用于测试）"""
        try:
            if node_name in self.nodes:
                self.nodes[node_name].set_value(value)
                logger.info(f"设置节点值: {node_name} = {value}")
            else:
                logger.warning(f"节点不存在: {node_name}")
        except Exception as e:
            logger.error(f"设置节点值失败: {e}")


def main():
    """主函数 - 启动测试服务器"""
    print("=" * 60)
    print("VWED OPC UA 测试服务器")
    print("=" * 60)
    
    # 创建并启动服务器
    server = OpcUaTestServer(host='localhost', port=4840)
    server.start_server()
    
    server_info = server.get_server_info()
    print(f"\n服务器信息:")
    print(f"  端点: {server_info['endpoint']}")
    print(f"  命名空间索引: {server_info['namespace_index']}")
    print(f"  运行状态: {server_info['running']}")
    
    # 显示节点信息
    print(f"\n测试节点列表:")
    node_info = server.get_node_info()
    if node_info:
        for name, info in node_info.items():
            print(f"  {name}:")
            print(f"    NodeId: ns={info['namespace_index']};{info['node_id']}")
            print(f"    Value: {info['value']} ({info['data_type']})")
    
    print(f"\n测试示例:")
    print("python -c \"")
    print("from services.online_script.built_in_modules.opc_ua_module import VWEDOpcUaModule")
    print("m = VWEDOpcUaModule('test')")
    print(f"print(m.read_opc_value_with_namespace({server_info['namespace_index']}, 'i=1001'))")
    print("\"")
    
    try:
        while True:
            time.sleep(10)
            # 显示当前动态数据状态
            node_info = server.get_node_info()
            if node_info:
                print(f"\n[{time.strftime('%H:%M:%S')}] 动态数据:")
                dynamic_nodes = ['counter', 'temperature', 'pressure', 'boolean_var']
                for node_name in dynamic_nodes:
                    if node_name in node_info:
                        value = node_info[node_name]['value']
                        print(f"  {node_name}: {value}")
            
    except KeyboardInterrupt:
        print("\n\n正在关闭服务器...")
        server.stop_server()
        print("服务器已关闭")


if __name__ == "__main__":
    main()