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

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

import time
import threading
from pymodbus.server.startstop import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext
from pymodbus.datastore.context import ModbusServerContext
import logging

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


class ModbusTestServer:
    """Modbus TCP 测试服务器"""
    
    def __init__(self, host='localhost', port=5020):
        self.host = host
        self.port = port
        self.server_thread = None
        self.running = False
        
        # 创建数据存储
        # 参数：(起始地址, 初始值列表)
        # 线圈 (0x区域) - 可读写的离散值
        coils = ModbusSequentialDataBlock(0, [False] * 100)
        
        # 离散输入 (1x区域) - 只读的离散值
        discrete_inputs = ModbusSequentialDataBlock(0, [True, False, True, False] * 25)
        
        # 输入寄存器 (3x区域) - 只读的16位值
        input_registers = ModbusSequentialDataBlock(0, [100, 200, 300, 400] * 25)
        
        # 保持寄存器 (4x区域) - 可读写的16位值
        holding_registers = ModbusSequentialDataBlock(0, [1000, 2000, 3000, 4000] * 25)
        
        # 创建从站上下文
        slave_context = ModbusSlaveContext(
            di=discrete_inputs,  # 离散输入
            co=coils,           # 线圈
            hr=holding_registers, # 保持寄存器
            ir=input_registers   # 输入寄存器
        )
        
        # 创建服务器上下文（支持从站ID 1-10）
        self.context = ModbusServerContext(slaves={
            1: slave_context,  # 从站ID 1
            2: slave_context,  # 从站ID 2 (共享同一个上下文，简化测试)
        }, single=False)
        
        # 设备信息
        self.identity = ModbusDeviceIdentification()
        self.identity.VendorName = 'VWED Test'
        self.identity.ProductCode = 'VWED-MODBUS-SIM'
        self.identity.VendorUrl = 'https://github.com/vwed'
        self.identity.ProductName = 'VWED Modbus TCP Simulator'
        self.identity.ModelName = 'Test Server v1.0'
        self.identity.MajorMinorRevision = '1.0.0'
        
        # 启动数据更新线程
        self.update_thread = None
        
    def start_server(self):
        """启动Modbus服务器"""
        if self.running:
            logger.warning("服务器已经在运行")
            return
            
        logger.info(f"启动Modbus TCP服务器: {self.host}:{self.port}")
        
        self.running = True
        
        # 启动数据更新线程
        self.update_thread = threading.Thread(target=self._update_data_loop, daemon=True)
        self.update_thread.start()
        
        # 启动服务器（在单独线程中）
        self.server_thread = threading.Thread(
            target=self._run_server, 
            daemon=True
        )
        self.server_thread.start()
        
        logger.info("Modbus TCP服务器启动成功")
        
    def _run_server(self):
        """运行服务器"""
        try:
            StartTcpServer(
                context=self.context,
                identity=self.identity,
                address=(self.host, self.port)
            )
        except Exception as e:
            logger.error(f"服务器运行错误: {e}")
            self.running = False
            
    def _update_data_loop(self):
        """更新测试数据的循环"""
        counter = 0
        while self.running:
            try:
                # 更新输入寄存器数据（模拟传感器读数）
                for slave_id in [1, 2]:
                    slave_context = self.context[slave_id]
                    
                    # 更新输入寄存器（模拟变化的传感器数据）
                    new_values = [
                        100 + counter % 100,      # 地址0: 100-199循环
                        200 + (counter * 2) % 200, # 地址1: 200-399循环  
                        300 + (counter * 3) % 300, # 地址2: 300-599循环
                        400 + (counter * 4) % 400, # 地址3: 400-799循环
                    ]
                    
                    for i, value in enumerate(new_values):
                        slave_context.setValues(3, i, [value])  # 3 = 输入寄存器
                    
                    # 更新离散输入（模拟开关状态）
                    discrete_values = [
                        counter % 2 == 0,         # 地址0: 每秒切换
                        counter % 4 < 2,          # 地址1: 每2秒切换
                        counter % 6 < 3,          # 地址2: 每3秒切换
                        counter % 8 < 4,          # 地址3: 每4秒切换
                    ]
                    
                    for i, value in enumerate(discrete_values):
                        slave_context.setValues(2, i, [value])  # 2 = 离散输入
                
                counter += 1
                time.sleep(1)  # 每秒更新一次
                
            except Exception as e:
                logger.error(f"数据更新错误: {e}")
                time.sleep(1)
                
    def stop_server(self):
        """停止服务器"""
        logger.info("正在停止Modbus TCP服务器...")
        self.running = False
        
    def get_server_info(self):
        """获取服务器信息"""
        return {
            'host': self.host,
            'port': self.port,
            'running': self.running,
            'slaves': list(self.context.slaves()) if hasattr(self.context, 'slaves') and callable(self.context.slaves) else [1, 2],
        }
        
    def set_coil_value(self, slave_id, address, value):
        """设置线圈值（用于测试）"""
        try:
            slave_context = self.context[slave_id]
            slave_context.setValues(1, address, [bool(value)])  # 1 = 线圈
            logger.info(f"设置线圈 slave={slave_id}, addr={address}, value={value}")
        except Exception as e:
            logger.error(f"设置线圈失败: {e}")
            
    def set_holding_register_value(self, slave_id, address, value):
        """设置保持寄存器值（用于测试）"""
        try:
            slave_context = self.context[slave_id]
            slave_context.setValues(4, address, [int(value)])  # 4 = 保持寄存器
            logger.info(f"设置保持寄存器 slave={slave_id}, addr={address}, value={value}")
        except Exception as e:
            logger.error(f"设置保持寄存器失败: {e}")
            
    def get_all_values(self, slave_id=1):
        """获取所有值（用于调试）"""
        try:
            slave_context = self.context[slave_id]
            
            # 读取各种类型的数据
            coils = slave_context.getValues(1, 0, 10)        # 线圈
            discrete = slave_context.getValues(2, 0, 10)     # 离散输入
            input_regs = slave_context.getValues(3, 0, 10)   # 输入寄存器
            holding_regs = slave_context.getValues(4, 0, 10) # 保持寄存器
            
            return {
                'coils': coils,
                'discrete_inputs': discrete,
                'input_registers': input_regs,
                'holding_registers': holding_regs
            }
        except Exception as e:
            logger.error(f"获取数据失败: {e}")
            return None


def main():
    """主函数 - 启动测试服务器"""
    print("=" * 60)
    print("VWED Modbus TCP 测试服务器")
    print("=" * 60)
    
    # 创建并启动服务器
    server = ModbusTestServer(host='localhost', port=5020)
    server.start_server()
    
    print(f"服务器信息: {server.get_server_info()}")
    print("\n测试数据布局:")
    print("- 线圈 (0x区域): 地址0-99, 初始值为False")
    print("- 离散输入 (1x区域): 地址0-99, 动态变化的True/False")
    print("- 输入寄存器 (3x区域): 地址0-99, 动态变化的数值")
    print("- 保持寄存器 (4x区域): 地址0-99, 初始值1000,2000,3000,4000...")
    print("\n支持的从站ID: 1, 2")
    print(f"\n连接地址: {server.host}:{server.port}")
    print("\n测试示例:")
    print("python -c \"")
    print("from services.online_script.built_in_modules.modbus_module import VWEDModbusModule")
    print("m = VWEDModbusModule('test')")
    print("print(m.read_holding_register('localhost', 5020, 1, 0, 2))")
    print("\"")
    
    try:
        while True:
            time.sleep(5)
            # 显示当前数据状态
            values = server.get_all_values(1)
            if values:
                print(f"\n[{time.strftime('%H:%M:%S')}] 从站1当前数据:")
                print(f"  输入寄存器[0-3]: {values['input_registers'][:4]}")
                print(f"  离散输入[0-3]: {values['discrete_inputs'][:4]}")
                print(f"  保持寄存器[0-3]: {values['holding_registers'][:4]}")
            
    except KeyboardInterrupt:
        print("\n\n正在关闭服务器...")
        server.stop_server()
        print("服务器已关闭")


if __name__ == "__main__":
    main()