# -*- coding: utf-8 -*-
"""
OPC数据读取服务
读取8个罐体的液位、密度、温度、流量
"""

import sys
import time
import threading
from datetime import datetime
from opcua import Client
from config import OPC, TANKS

# 全局存储最新数据
latest_data = {}
last_update = None
is_connected = False
error_message = None

class OPCReader:
    def __init__(self):
        self.client = None
        self.running = False
        self.thread = None
    
    def connect(self):
        """连接OPC服务器"""
        global is_connected, error_message
        try:
            if not OPC['enable']:
                is_connected = False
                error_message = "OPC采集已禁用（开发模式）"
                return False
            
            self.client = Client(OPC['server_url'])
            self.client.connect()
            is_connected = True
            error_message = None
            print(f"[{datetime.now()}] OPC服务器连接成功: {OPC['server_url']}")
            return True
        except Exception as e:
            is_connected = False
            error_message = f"OPC连接失败: {str(e)}"
            print(error_message, file=sys.stderr)
            return False
    
    def disconnect(self):
        """断开连接"""
        if self.client:
            try:
                self.client.disconnect()
            except:
                pass
        self.running = False
    
    def read_tank_data(self, tank):
        """读取单个罐体数据"""
        data = {
            'level': None,
            'density': None,
            'temperature': None,
            'flow': None
        }
        
        try:
            # 读取液位
            if tank.get('node_id'):
                node = self.client.get_node(tank['node_id'])
                data['level'] = node.get_value()
            
            # 读取密度
            if tank.get('density_node'):
                node = self.client.get_node(tank['density_node'])
                data['density'] = node.get_value()
            
            # 读取温度
            if tank.get('temp_node'):
                node = self.client.get_node(tank['temp_node'])
                data['temperature'] = node.get_value()
            
            # 读取流量
            if tank.get('flow_node'):
                node = self.client.get_node(tank['flow_node'])
                data['flow'] = node.get_value()
        
        except Exception as e:
            print(f"读取罐体 {tank['id']} 数据失败: {str(e)}", file=sys.stderr)
        
        return data
    
    def read_all(self):
        """读取所有罐体数据"""
        global latest_data, last_update
        result = {}
        
        for tank in TANKS:
            tank_id = str(tank['id'])
            result[tank_id] = self.read_tank_data(tank)
            result[tank_id]['info'] = tank
        
        latest_data = result
        last_update = datetime.now()
        return result
    
    def start_background_polling(self):
        """后台轮询"""
        self.running = True
        
        def polling_loop():
            global is_connected
            while self.running:
                if not is_connected:
                    self.connect()
                    time.sleep(OPC['update_interval'])
                    continue
                
                try:
                    self.read_all()
                except Exception as e:
                    global error_message
                    error_message = f"数据读取异常: {str(e)}"
                    print(error_message, file=sys.stderr)
                    is_connected = False
                
                time.sleep(OPC['update_interval'])
        
        self.thread = threading.Thread(target=polling_loop, daemon=True)
        self.thread.start()
        print(f"OPC后台轮询启动，间隔 {OPC['update_interval']} 秒")

# 全局单例
opc_reader = OPCReader()

def get_latest_data():
    """获取最新数据"""
    # OPC禁用模式下，每次获取都重新生成随机数据，保证动态跳动
    if not OPC['enable']:
        generate_mock_data()
    
    return {
        'data': latest_data,
        'last_update': last_update.isoformat() if last_update else datetime.now().isoformat(),
        'connected': is_connected,
        'error': error_message
    }

def generate_mock_data():
    """生成模拟数据（带随机波动）"""
    import random
    # 给每个罐体加上随机变化，让数据跳动更明显
    mock_data = {}
    base_level = {
        1: 4.2, 2: 7.5, 3: 9.1, 4: 12.3,
        5: 6.8, 6: 11.2, 7: 8.5, 8: 13.6
    }
    for tank in TANKS:
        tank_id = str(tank['id'])
        # 基础液位加上随机波动 ±0.5米，变化明显能看到跳动
        base = base_level.get(tank['id'], random.uniform(2, 14))
        level_var = random.uniform(-0.5, 0.5)
        
        mock_data[tank_id] = {
            'level': round(base + level_var, 2),
            'density': round(random.uniform(0.800, 0.880), 3),
            'temperature': round(random.uniform(15.0, 22.0), 1),
            'flow_in': round(random.uniform(5, 35), 1),
            'flow_out': round(random.uniform(5, 35), 1),
            'info': tank
        }
    global latest_data
    latest_data = mock_data
    global last_update
    last_update = datetime.now()
    print("生成模拟数据完成（带波动），共8个罐体")

def start():
    """启动OPC读取"""
    if OPC['enable']:
        opc_reader.connect()
        opc_reader.start_background_polling()
    else:
        # 开发模式：生成模拟数据
        import random
        print("OPC采集已禁用，使用模拟数据")
        generate_mock_data()
