"""Mini orchestrator to run the VideoReceiverSFP module for development.

This script acts as a small test harness: it starts the `SfpConnectorModule`
in simulated mode (reading images from a folder) or network mode and hooks a
simple GUI viewer and runs for a configurable duration.
"""
import argparse
import os
import sys
import time
import logging

from .sfp_module import SfpConnectorModule


def run_orchestrator():
    parser = argparse.ArgumentParser(prog="VideoReceiverSFP.orchestrator")
    parser.add_argument("--sim-dir", default=None, help="Directory with sample images for simulation (if not provided and no --host/--port, uses 'dumps')")
    parser.add_argument("--fps", type=int, default=5, help="Frames per second for simulated stream")
    parser.add_argument("--duration", type=int, default=None, help="Seconds to run the demo (omit for indefinite run)")
    parser.add_argument("--host", default=None, help="Host/IP to bind and listen for SFP UDP (network mode)")
    parser.add_argument("--port", type=int, default=None, help="UDP port to listen for SFP (network mode)")
    parser.add_argument("--no-gui", action="store_true", help="Run in headless mode (no GUI)")
    parser.add_argument("--normalize", choices=["none", "cp", "autocontrast"], default="none", help="Normalize raw frames before display: 'cp' uses controlpanel.normalize_image if available, 'autocontrast' uses PIL fallback")
    parser.add_argument("--verbose", action="store_true", help="Enable verbose DEBUG logging")
    parser.add_argument("--compact", action="store_true", help="Start viewers in compact mode (hide controls, accessible via right-click)")
    parser.add_argument(
        '--image-type', '--type', dest='image_type', type=str, choices=['MFD', 'SAR', 'ALL'], default='ALL',
        help='Filter for a specific image type (MFD or SAR). Default is ALL.'
    )
    args = parser.parse_args()

    # Viewer placeholders
    viewer = None
    sar_viewer = None
    root = None  # Tk root window reference for embedded mode

    # If we're running under a debugger (VS Code), prefer the local
    # `dumps/` simulation directory for convenience so the debug
    # configuration shows images without a live sender.
    try:
        in_debugger = sys.gettrace() is not None or os.environ.get("VSCODE_DEBUG")
    except Exception:
        in_debugger = False

    if in_debugger and args.sim_dir is None and args.host is None and args.port is None:
        dumps_dir = os.path.join(os.getcwd(), "dumps")
        if os.path.isdir(dumps_dir):
            print("Debugger detected — forcing sim-mode using dumps/ for convenience")
            args.sim_dir = dumps_dir

    # Initialize module and determine mode (network vs sim)
    module = SfpConnectorModule()
    init_cfg = {"fps": args.fps}
    if args.normalize and args.normalize != 'none':
        init_cfg['normalize'] = args.normalize
    if args.image_type != 'ALL':
        init_cfg['image_type_filter'] = args.image_type.upper()

    # Try to pull defaults from controlpanel config
    default_host = None
    default_port = None
    try:
        from controlpanel import config as cp_config
        default_host = getattr(cp_config, 'DEFAULT_SER_IP', None)
        default_port = getattr(cp_config, 'DEFAULT_SER_PORT', None)
    except Exception:
        default_host = None
        default_port = None

    host = args.host if args.host is not None else default_host
    port = args.port if args.port is not None else default_port

    if host and port and args.sim_dir is None:
        init_cfg.update({"host": host, "port": int(port)})
        module.initialize(init_cfg)
        print(f"Network mode: listening on {host}:{port}")
    else:
        sim_dir = args.sim_dir if args.sim_dir is not None else os.path.join(os.getcwd(), 'dumps')
        if not os.path.isdir(sim_dir):
            print(f"WARNING: sim directory '{sim_dir}' not found; no frames will be loaded")
        init_cfg['sim_dir'] = sim_dir
        module.initialize(init_cfg)
        print(f"Simulation mode: loading frames from {sim_dir}")

    # Configure basic logging to console
    log_level = logging.DEBUG if args.verbose else logging.INFO
    logging.basicConfig(level=log_level, format="[%(levelname)s] %(message)s")
    logging.info("VideoReceiverSFP: initialized module; mode=%s", "network" if host and port else "sim")

    # Create GUI viewers if not in headless mode
    if not args.no_gui:
        try:
            # Create a single top-level window that hosts both viewers
            import tkinter as tk
            from tkinter import ttk
            try:
                from ..gui.viewer_with_params import SfpViewerWithParams
                from ..gui.viewer_sar import SfpSarViewer

                root = tk.Tk()
                root.title("VideoReceiverSFP - Orchestrator")
                # Set minimum window size: 2x(484 image + ~250 controls) + padding
                root.geometry("1500x600")
                root.minsize(1400, 550)

                main_frame = ttk.Frame(root)
                main_frame.pack(fill="both", expand=True, padx=6, pady=6)

                # Left and right labelframes (equal weight)
                left_box = ttk.Labelframe(main_frame, text="MFD Viewer")
                right_box = ttk.Labelframe(main_frame, text="SAR Viewer")
                left_box.grid(row=0, column=0, sticky="nsew", padx=(0,4), pady=2)
                right_box.grid(row=0, column=1, sticky="nsew", padx=(4,0), pady=2)
                # Set minimum column widths to ensure 484px images + controls are visible
                main_frame.columnconfigure(0, weight=1, minsize=700)
                main_frame.columnconfigure(1, weight=1, minsize=700)
                main_frame.rowconfigure(0, weight=1)

                # Callbacks
                def on_mfd_param_changed(param_type, name, value):
                    logging.info(f"MFD param changed: {param_type} {name}={value}")
                    try:
                        if param_type == 'save_png':
                            module.set_save_png(bool(value))
                            return
                        if param_type == 'save_bin':
                            module.set_save_bin(bool(value))
                            return
                    except Exception:
                        logging.getLogger().exception('Failed to set save flags on module')
                    try:
                        new_lut = viewer.get_mfd_lut()
                        if new_lut is not None:
                            module.update_mfd_lut(new_lut)
                    except Exception:
                        logging.getLogger().exception('Failed to update MFD LUT from viewer')

                def on_sar_param_changed(param_type, name, value):
                    logging.info(f"SAR param changed: {param_type} {name}={value}")
                    try:
                        if param_type == 'brightness':
                            module.set_sar_brightness(int(value))
                        elif param_type == 'contrast':
                            module.set_sar_contrast(int(value))
                        elif param_type == 'autocontrast':
                            module.set_sar_autocontrast(bool(value))
                        elif param_type == 'save_png':
                            module.set_sar_save_png(bool(value))
                    except Exception:
                        logging.getLogger().exception('Failed to set SAR parameter on module')

                # Instantiate embedded viewers inside the Labelframes
                viewer = SfpViewerWithParams(on_mfd_param_changed=on_mfd_param_changed, master=left_box, compact=args.compact)
                sar_viewer = SfpSarViewer(on_sar_param_changed=on_sar_param_changed, master=right_box, compact=args.compact)
                logging.info("VideoReceiverSFP: embedded MFD and SAR viewers created")

            except ImportError:
                # Fallback to old simple viewer embedded in a single frame
                from ..gui.viewer import SfpViewer
                root = tk.Tk()
                main_frame = ttk.Frame(root)
                main_frame.pack(fill="both", expand=True)
                left_box = ttk.Labelframe(main_frame, text="Viewer")
                left_box.pack(fill="both", expand=True)
                viewer = SfpViewer(window_title="SFP Viewer")
                logging.info("VideoReceiverSFP: using simple viewer (no params)")
        except Exception:
            logging.exception("Failed to initialize GUI viewer; continuing headless")
            viewer = None

    # Register callbacks: if we have MFD/SAR viewers, use specialized callbacks
    # Register callbacks: prefer specialized MFD and SAR callbacks when both viewers exist.
    if viewer is not None and sar_viewer is not None:
        try:
            module.register_mfd_callback(viewer.show_frame)
            module.register_sar_callback(sar_viewer.show_frame)
            try:
                module.register_sar_metadata_callback(sar_viewer.show_metadata)
            except Exception:
                pass
            logging.getLogger().debug('Registered specialized MFD and SAR callbacks')
        except Exception:
            logging.getLogger().exception('Failed registering specialized callbacks')
    else:
        # Fallback: register a single generic callback to the available viewer
        def on_frame(frame):
            try:
                if viewer is not None:
                    viewer.show_frame(frame)
                elif sar_viewer is not None:
                    sar_viewer.show_frame(frame)
            except Exception:
                logging.getLogger().exception('Error in generic on_frame')

        module.register_callback(on_frame)
    module.start_session()
    logging.info("VideoReceiverSFP: session started; status=%s", module.get_status())

    # If duration is None -> run indefinitely until user stops (Ctrl-C)
    duration = args.duration
    try:
        # If we have an embedded GUI (root exists), run the Tk mainloop
        if root is not None:
            if duration is None:
                # Run indefinitely until window closed
                root.mainloop()
            else:
                # Run with timeout
                def stop_after_duration():
                    time.sleep(duration)
                    logging.info(f"Duration {duration}s elapsed; stopping")
                    try:
                        root.quit()
                    except Exception:
                        pass
                import threading
                timer = threading.Thread(target=stop_after_duration, daemon=True)
                timer.start()
                root.mainloop()
        elif viewer is not None:
            # Standalone viewer case (owns its own root)
            if duration is None:
                viewer.run()
            else:
                # Duration provided: handle viewers that accept duration or not
                if hasattr(viewer, 'run'):
                    if 'duration' in viewer.run.__code__.co_varnames:
                        viewer.run(duration=duration)
                    else:
                        import threading
                        def stop_after_duration():
                            time.sleep(duration)
                            logging.info(f"Duration {duration}s elapsed; stopping viewer")
                            try:
                                viewer.stop()
                            except Exception:
                                pass
                        timer = threading.Thread(target=stop_after_duration, daemon=True)
                        timer.start()
                        viewer.run()
                else:
                    # Viewer has no run method; wait for duration then exit
                    time.sleep(duration)
        else:
            # Headless mode
            if duration is None:
                # Run forever until interrupted
                while True:
                    time.sleep(0.5)
            else:
                start = time.time()
                while time.time() - start < duration:
                    time.sleep(0.5)
    finally:
        module.stop_session()
        logging.info("VideoReceiverSFP: session stopped")


if __name__ == "__main__":
    run_orchestrator()
