import time
import sys
import os
import argparse
import logging
import tkinter as tk
from .core.network import UdpHandler
from .core.dispatcher import MessageDispatcher
from .core.scheduler import TrafficScheduler
from .core.controller import RadarController
from .utils.printer import dump_message
from .gui.main_window import BusMonitorApp
from .lib1553.constants import StandbyStatus, IntBitStatus, DegradedStatus

logger = logging.getLogger(__name__)

#Configuration
RX_IP = os.getenv("PYBM_RX_IP", "127.0.0.1")
RX_PORT = int(os.getenv("PYBM_RX_PORT", str(61553)))
TARGET_IP = os.getenv("PYBM_TARGET_IP", "127.0.0.1")
TARGET_PORT = int(os.getenv("PYBM_TARGET_PORT", "51553"))


def main_cli():
    """Command-line interface mode (original behavior)"""
    print("--------------------------------------------------")
    print(" PyBusMonitor1553 - Active Controller (CLI Mode)")
    print("--------------------------------------------------")
    
    # 1. Initialize Components
    dispatcher = MessageDispatcher()
    network = UdpHandler(rx_ip=RX_IP, rx_port=RX_PORT)

    # 2. Initialize Radar Logic Controller
    radar_ctrl = RadarController()

    # 3. Initialize Scheduler with the Controller
    scheduler = TrafficScheduler(network, radar_ctrl, TARGET_IP, TARGET_PORT)

    # 4. Define the callback for received messages
    def on_packet(data, addr):
        header, messages = dispatcher.parse_packet(data)
        
        if messages:
            for msg in messages:
                if msg.IS_TRANSMIT:
                    print(f"\n[RX] {msg.__class__.__name__} from RT{header.ta if header else '?'}")
                    dump_message(msg)
        elif header and header.errors != 0:
            print(f"[RX] Server Error Code: {header.errors}")

    # 5. Start everything
    network.register_callback(on_packet)
    network.start()
    scheduler.start()

    print(f"System Running.")
    print(f"RX: {RX_IP}:{RX_PORT} | TX: {TARGET_IP}:{TARGET_PORT}")
    print("Press Ctrl+C to stop.")

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("\nStopping...")
    finally:
        scheduler.stop()
        network.stop()
        sys.exit(0)


def main_gui():
    """Graphical user interface mode"""
    # Enable quiet mode for scheduler
    from .core import scheduler as sched_module
    sched_module.QUIET_MODE = True
    
    # Initialize Tkinter
    root = tk.Tk()
    app = BusMonitorApp(root)
    
    # Log banner AFTER TkinterLogger is initialized
    logger.info("=" * 50)
    logger.info("PyBusMonitor1553 - Active Controller (GUI Mode)")
    logger.info("=" * 50)
    
    # Initialize Components
    dispatcher = MessageDispatcher()
    network = UdpHandler(rx_ip=RX_IP, rx_port=RX_PORT)
    radar_ctrl = RadarController()
    scheduler = TrafficScheduler(network, radar_ctrl, TARGET_IP, TARGET_PORT)
    
    # Counters for status bar
    tx_count = [0]
    rx_count = [0]
    
    # Define the callback for received messages
    def on_packet(data, addr):
        header, messages = dispatcher.parse_packet(data)
        rx_count[0] += 1
        
        if messages:
            for msg in messages:
                if msg.IS_TRANSMIT:
                    msg_name = msg.__class__.__name__
                    # Convert MsgB6 -> B6, MsgA1 -> A1, etc.
                    short_name = msg_name.replace("Msg", "")
                    
                    # Log B7 status messages for debugging
                    if short_name == "B7":
                        logger.debug("=== Received B7 Status Tellback ===")
                        try:
                            mode_tb = msg.master_mode_tb
                            mode_name = mode_tb.name if hasattr(mode_tb, 'name') else str(mode_tb)
                            logger.debug(f"  master_mode_tb = {mode_name} ({mode_tb})")
                            
                            stby = msg.standby_status
                            stby_name = stby.name if hasattr(stby, 'name') else str(stby)
                            logger.debug(f"  standby_status = {stby_name} ({stby})")
                            
                            desg = msg.designation_status
                            desg_name = desg.name if hasattr(desg, 'name') else str(desg)
                            logger.debug(f"  designation_status = {desg_name}")
                            
                            ibit = msg.int_bit_status
                            ibit_name = ibit.name if hasattr(ibit, 'name') else str(ibit)
                            logger.debug(f"  int_bit_status = {ibit_name}")
                            
                            freeze = msg.freeze_status
                            freeze_name = freeze.name if hasattr(freeze, 'name') else str(freeze)
                            logger.debug(f"  freeze_status = {freeze_name}")
                            
                            degr = msg.degraded_status
                            degr_name = degr.name if hasattr(degr, 'name') else str(degr)
                            logger.debug(f"  degraded_status = {degr_name}")
                            
                            # Warning if standby is still ON
                            if stby != StandbyStatus.OFF and stby != 0:
                                logger.warning(f"⚠ Radar still in STANDBY (status={stby_name})")
                            
                            # Warning if IBIT in progress or degraded
                            if ibit != IntBitStatus.NORMAL and ibit != 0:
                                logger.warning(f"⚠ IBIT in progress (status={ibit_name})")
                            if degr != DegradedStatus.NORMAL and degr != 0:
                                logger.warning(f"⚠ Radar degraded (status={degr_name})")
                        except Exception as e:
                            logger.error(f"Error logging B7 details: {e}")
                    
                    # Extract raw words if available
                    raw_words = []
                    if hasattr(msg, '_raw_data') and msg._raw_data:
                        import struct
                        data_bytes = msg._raw_data
                        for i in range(0, len(data_bytes), 2):
                            if i + 1 < len(data_bytes):
                                word = struct.unpack('<H', data_bytes[i:i+2])[0]
                                raw_words.append(word)
                    
                    # Accoda aggiornamento invece di usare root.after() diretto
                    app.queue_message_update(short_name, msg, raw_words)
        
        # Accoda aggiornamento status invece di usare root.after() diretto
        app.queue_status_update(True, tx_count[0], rx_count[0], "")
    
    # Wrap scheduler send to count TX
    original_send = network.send
    def counted_send(data, ip, port):
        tx_count[0] += 1
        return original_send(data, ip, port)
    network.send = counted_send
    
    # Register callback for sent messages (A messages)
    def on_message_sent(msg):
        if not msg.IS_TRANSMIT:  # BC->RT messages (A messages)
            msg_name = msg.__class__.__name__
            short_name = msg_name.replace("Msg", "")
            
            # Extract raw words from current message state
            raw_words = []
            if hasattr(msg, '_data'):
                raw_words = list(msg._data)[:32]  # Copy first 32 words
            
            # Accoda aggiornamento invece di usare root.after() diretto
            app.queue_message_update(short_name, msg, raw_words)
    
    scheduler.register_sent_callback(on_message_sent)
    
    # Wire up RUN/STOP button actions
    def on_connect():
        """Called when RUN button is pressed"""
        logger.info("Applying default radar configuration...")
        radar_ctrl.apply_defaults()  # Apply defaults only when RUN is pressed
        
        logger.info("Starting network and scheduler...")
        network.start()
        scheduler.start()
        app.update_connection_status(True, tx_count[0], rx_count[0], "")
    
    def on_disconnect():
        """Called when STOP button is pressed"""
        logger.info("Stopping scheduler and network...")
        scheduler.stop()
        network.stop()
        app.update_connection_status(False, tx_count[0], rx_count[0], "")
    
    app._on_connect = on_connect
    app._on_disconnect = on_disconnect
    
    # Register callback but DON'T start automatically - wait for RUN button
    network.register_callback(on_packet)
    
    # Update initial status (disconnected)
    app.update_connection_status(False, 0, 0, "")
    
    logger.info(f"GUI Ready - RX: {RX_IP}:{RX_PORT} | TX: {TARGET_IP}:{TARGET_PORT}")
    logger.info("Press RUN to start communication")
    
    # Handle window close
    def on_closing():
        if scheduler._running:
            scheduler.stop()
        if network._running:
            network.stop()
        app.shutdown()
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", on_closing)
    
    # Run the GUI main loop
    try:
        root.mainloop()
    except KeyboardInterrupt:
        on_closing()


def main():
    """Main entry point with mode selection"""
    global TARGET_IP, TARGET_PORT
    
    parser = argparse.ArgumentParser(
        description='PyBusMonitor1553 - MIL-STD-1553 Bus Monitor',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
Examples:
  python -m pybusmonitor1553           # Launch GUI mode (default)
  python -m pybusmonitor1553 --cli     # Launch CLI mode
  python -m pybusmonitor1553 --gui     # Launch GUI mode explicitly
        '''
    )
    parser.add_argument('--cli', action='store_true', 
                        help='Run in command-line interface mode')
    parser.add_argument('--gui', action='store_true', 
                        help='Run in graphical user interface mode (default)')
    parser.add_argument('--target', type=str, default=None,
                        help=f'Target IP address (default: {TARGET_IP})')
    parser.add_argument('--port', type=int, default=None,
                        help=f'Target port (default: {TARGET_PORT})')
    
    args = parser.parse_args()
    
    # Update globals if specified
    if args.target:
        TARGET_IP = args.target
    if args.port:
        TARGET_PORT = args.port
    
    if args.cli:
        main_cli()
    else:
        main_gui()
        
if __name__ == "__main__":
    main()