import time
import network
import espnow
from machine import Pin

class ESPNowReceiver:
    """ESP-NOW Receiver simplified class with high-precision frequency statistics and data parsing"""
    
    def __init__(self, sender_mac, debug_print=False):
        """
        Initialize the receiver
        :param sender_mac: Sender MAC address (bytes format, e.g., b'\xec\xe34+\xce\x08')
        :param debug_print: Whether to enable debug printing (default False)
        """
        # Basic Configuration
        self.sender_mac = sender_mac
        self.debug_print = debug_print
        
        # Statistics variables (Microsecond precision)
        self.recv_count = 0
        self.last_stat_ticks = time.ticks_us()
        self.stat_interval_us = 1000000  # 1-second statistics interval
        
        # Initialize ESP-NOW
        self._init_espnow()
    
    def _init_espnow(self):
        """Initialize ESP-NOW communication"""
        # Start WLAN STA mode
        self.sta = network.WLAN(network.WLAN.IF_STA)
        self.sta.active(True)
        self.sta.disconnect()
        
        # Initialize ESP-NOW
        self.espnow = espnow.ESPNow()
        self.espnow.active(True)
        
        # Add sender as peer
        try:
            self.espnow.add_peer(self.sender_mac)
            print(f"Receiver initialized | Local MAC: {self.sta.config('mac')}")
            print(f"Bound to Sender MAC: {self.sender_mac}")
        except Exception as e:
            raise RuntimeError(f"ESP-NOW initialization failed: {e}")
    
    def parse_data(self, data_str):
        """
        Parse received data (Strictly matches the sender's format)
        :param data_str: Decoded string data
        :return: Structured dictionary or None (if parsing fails)
        """
        try:
            parts = data_str.strip().split('|')
            if len(parts) != 5:
                if self.debug_print:
                    print(f"Format Error (Field count): {data_str[:50]}...")
                return None
            
            # Parse and return structured data
            return {
                "device_state": parts[0],
                "vrx_l": int(parts[1].split(',')[0]),
                "vry_l": int(parts[1].split(',')[1]),
                "vrx_r": int(parts[1].split(',')[2]),
                "vry_r": int(parts[1].split(',')[3]),
                "sw_l": int(parts[2].split(',')[0]),
                "sw_r": int(parts[2].split(',')[1]),
                "t_l": int(parts[3].split(',')[0]),
                "t_r": int(parts[3].split(',')[1]),
                "check_code": parts[4]
            }
        except Exception as e:
            if self.debug_print:
                print(f"Parsing Failed: {e} | Data: {data_str[:50]}...")
            return None
    
    def _print_statistics(self):
        """Print high-precision reception frequency statistics"""
        current_ticks = time.ticks_us()
        actual_interval = time.ticks_diff(current_ticks, self.last_stat_ticks) / 1000000
        recv_freq = self.recv_count / actual_interval if actual_interval > 0 else 0
        
        print(f"=== Stats: {self.recv_count} recvs | Duration: {actual_interval:.3f}s | Freq: {recv_freq:.2f}Hz ===")
        
        # Reset statistics
        self.recv_count = 0
        self.last_stat_ticks = current_ticks
    
    def run(self, callback=None):
        """
        Start reception loop (Blocking)
        :param callback: Optional callback function triggered on data receipt, passes parsed dict
        """
        print(f"Receiver Started | Debug Mode: {'ON' if self.debug_print else 'OFF'}")
        print("Listening for data...")
        
        while True:
            # Receive data (Continuous listening)
            host, data = self.espnow.recv()
            
            if data:
                try:
                    # Decode and increment count
                    data_str = data.decode('utf-8')
                    self.recv_count += 1
                    
                    # Debug print
                    if self.debug_print:
                        print(f"True,{data_str[:50]}")
                    
                    # Parse data and trigger callback
                    parsed_data = self.parse_data(data_str)
                    if callback and parsed_data:
                        callback(parsed_data)
                    
                except UnicodeError:
                    if self.debug_print:
                        print(f"Decoding Failed: {data[:20]}...")
            
            # Periodically print statistics
            if time.ticks_diff(time.ticks_us(), self.last_stat_ticks) >= self.stat_interval_us:
                if self.debug_print:
                    self._print_statistics()
                

# ---------------------- External Usage Example ----------------------
if __name__ == "__main__":
    # 1. Configure Sender MAC (Replace with your actual sender's MAC address)
    SENDER_MAC = b'\xec\xe34+\xce\x08'
    
    # 2. Define callback function for business logic (e.g., motor control)
    def data_callback(parsed_data):
        """
        Data received callback: Add motor control or other logic here.
        Example: Print key data (replace with actual control logic in production)
        """
        # print(f"State: {parsed_data['device_state']} | L-Joy: ({parsed_data['vrx_l']}, {parsed_data['vry_l']})")
        pass
    
    # 3. Create receiver instance and start
    try:
        receiver = ESPNowReceiver(
            sender_mac=SENDER_MAC,
            debug_print=False  # True = Enable debug prints, False = Only statistics
        )
        # Start receiving (Blocking mode)
        receiver.run(callback=data_callback)
    except KeyboardInterrupt:
        print("Receiver stopped by user")
    except Exception as e:
        print(f"Runtime Exception: {e}")