import threading
import time
from asyncua.sync import Client

class wtopcua:
    def __init__(self, url):
        self.url = url
        self.client = None
        self.node = []
        self.featureName = None
        self.feaDict = {}
        self.connected = False
        self.reconnect_thread = None
        self.running = False

    def connect(self):
        try:
            self.client = Client(self.url, 5)
            self.client.connect()
            self.connected = True
        except Exception as e:
            self.connected = False
            print(f"Connection failed: {e}")

    def disconnect(self):
        if self.client:
            self.client.disconnect()
            self.connected = False
            print("Disconnected from server")
            self.client = None

    def get_node_and_feature_from_opcuacfg(self, config):
        for cfg in config:
            ns = cfg["node_ns"]
            s =  cfg["node_s"]
            for rm in cfg['linkrm']:
                self.node.append(f'ns={ns};{s}={rm}') 
            self.featureName = cfg['feature']
        self.start_reconnect_thread()
            
    def read_node_value(self, node_id: str) -> any:
        try:
            node = self.client.get_node(node_id)
            value = node.read_value()
            return value
        except Exception as e:
            print(f"Error reading node {node_id}: {e}")
            return None

    def write_node_value(self, node_id: str, value: any):
        try:
            node = self.client.get_node(node_id)
            node.write_value(value)
        except Exception as e:
            print(f"Error writing to node {node_id}: {e}")

    def get_opcua_data(self):
        if self.client:
            for index, s_node in enumerate(self.node):
                self.feaDict[self.featureName[index]] = self.read_node_value(s_node)   

    def get_opcua_rm_data(self):
        if self.client:
            return self.feaDict 
        return []
    
    def start_reconnect_thread(self):
        self.running = True
        self.reconnect_thread = threading.Thread(target=self.reconnect_loop)
        self.reconnect_thread.daemon = True
        self.reconnect_thread.start()

    def stop_reconnect_thread(self):
        self.running = False
        if self.reconnect_thread:
            self.reconnect_thread.join()
            self.reconnect_thread = None

    def reconnect_loop(self):
        while self.running:
            if not self.connected:
                self.connect()
            time.sleep(60)

    def __del__(self):
        self.stop_reconnect_thread()
        self.disconnect()