"""Dispatch logic for decoded frames (MFD/SAR/generic).

Provides `dispatch_frame(module, frame, leader)` which encapsulates
recording, saving previews, and invoking registered callbacks.
"""
from typing import Any, Optional
import logging
import os
import time
import pathlib

try:
    from PIL import Image, ImageOps, ImageEnhance
except Exception:
    Image = None
    ImageOps = None
    ImageEnhance = None


def dispatch_frame(module: Any, frame: Any, leader: Optional[Any]) -> None:
    """Handle a decoded frame: start/ write video, save previews, and call callbacks.

    `module` is the `SfpConnectorModule` instance.
    """
    try:
        # Determine image type
        image_type_id = None
        try:
            if leader is not None:
                image_type_id = int(leader.HEADER_DATA.TYPE)
        except Exception:
            image_type_id = None

        # SAR path
        if image_type_id == getattr(module, 'IMAGE_TYPE_SAR', 2):
            try:
                if Image is not None and hasattr(frame, 'copy'):
                    sar_img = frame.copy()
                    if getattr(module, '_sar_autocontrast', False) and ImageOps is not None:
                        try:
                            sar_img = ImageOps.autocontrast(sar_img)
                        except Exception:
                            pass
                    try:
                        bf = max(0.0, 1.0 + (float(getattr(module, '_sar_brightness', 0)) / 100.0))
                        cf = max(0.0, 1.0 + (float(getattr(module, '_sar_contrast', 0)) / 100.0))
                        if bf != 1.0 and ImageEnhance is not None:
                            sar_img = ImageEnhance.Brightness(sar_img).enhance(bf)
                        if cf != 1.0 and ImageEnhance is not None:
                            sar_img = ImageEnhance.Contrast(sar_img).enhance(cf)
                    except Exception:
                        pass

                    # save sar png
                    if getattr(module, '_sar_save_png', False):
                        try:
                            if getattr(module, '_dump_manager', None) is not None:
                                saved = module._dump_manager.save_preview_from_pil(sar_img, category='sar', fmt='png')
                                if saved:
                                    logging.getLogger().info("VideoReceiverSFP: saved sar png %s", saved)
                            else:
                                ts = time.strftime('%Y%m%d_%H%M%S') + (f"_{int(time.time() * 1000) % 1000:03d}")
                                dumps_dir = getattr(module, '_dumps_dir', os.path.join(os.getcwd(), 'dumps'))
                                os.makedirs(dumps_dir, exist_ok=True)
                                pngpath = os.path.join(dumps_dir, f'VideoReceiverSFP_sar_{ts}.png')
                                sar_img.save(pngpath)
                                module._saved_sar_pngs.append(pngpath)
                                while len(module._saved_sar_pngs) > module._dump_keep:
                                    old = module._saved_sar_pngs.popleft()
                                    try:
                                        pathlib.Path(old).unlink()
                                    except Exception:
                                        pass
                        except Exception:
                            logging.getLogger().exception("VideoReceiverSFP: failed saving sar png frame")

                    # sar video
                    try:
                        if getattr(module, '_record_sar_video', False) and getattr(module, '_dump_manager', None) is not None:
                            if not getattr(module, '_sar_video_active', False):
                                try:
                                    w, h = None, None
                                    if Image is not None and hasattr(sar_img, 'size'):
                                        w, h = sar_img.size
                                    else:
                                        try:
                                            import numpy as _np
                                            arr = _np.asarray(sar_img)
                                            if arr is not None and arr.ndim >= 2:
                                                h, w = arr.shape[0], arr.shape[1]
                                        except Exception:
                                            pass
                                    if w and h:
                                        started = module._dump_manager.start_video_record('sar', w, h, fps=getattr(module, '_video_fps', 20))
                                        if started:
                                            module._sar_video_active = True
                                            try:
                                                logging.getLogger().info("VideoReceiverSFP: started SAR video writer (%dx%d @ %s FPS)", w, h, getattr(module, '_video_fps', 20))
                                            except Exception:
                                                pass
                                except Exception:
                                    logging.getLogger().exception("VideoReceiverSFP: failed to start sar video writer")
                            if getattr(module, '_sar_video_active', False):
                                try:
                                    module._dump_manager.write_video_frame(sar_img, 'sar')
                                except Exception:
                                    logging.getLogger().exception("VideoReceiverSFP: failed writing sar frame to video")
                    except Exception:
                        pass

                    # deliver to callbacks
                    for scb in list(getattr(module, '_sar_callbacks', [])):
                        try:
                            scb(sar_img)
                        except Exception:
                            pass
            except Exception:
                logging.getLogger().exception("VideoReceiverSFP: error processing SAR image for SAR callbacks")

        # MFD path
        if image_type_id == getattr(module, 'IMAGE_TYPE_MFD', 1):
            try:
                try:
                    if getattr(module, '_record_mfd_video', False) and getattr(module, '_dump_manager', None) is not None:
                        if not getattr(module, '_mfd_video_active', False):
                            try:
                                w, h = None, None
                                if Image is not None and hasattr(frame, 'size'):
                                    w, h = frame.size
                                else:
                                    try:
                                        import numpy as _np
                                        arr = _np.asarray(frame)
                                        if arr is not None and arr.ndim >= 2:
                                            h, w = arr.shape[0], arr.shape[1]
                                    except Exception:
                                        pass
                                if w and h:
                                    started = module._dump_manager.start_video_record('mfd', w, h, fps=getattr(module, '_video_fps', 20))
                                    if started:
                                        module._mfd_video_active = True
                                        try:
                                            logging.getLogger().info("VideoReceiverSFP: started MFD video writer (%dx%d @ %s FPS)", w, h, getattr(module, '_video_fps', 20))
                                        except Exception:
                                            pass
                            except Exception:
                                logging.getLogger().exception('VideoReceiverSFP: failed to start mfd video writer')
                        if getattr(module, '_mfd_video_active', False):
                            try:
                                module._dump_manager.write_video_frame(frame, 'mfd')
                            except Exception:
                                logging.getLogger().exception('VideoReceiverSFP: failed writing mfd frame to video')
                            try:
                                if not getattr(module, '_mfd_callbacks', False):
                                    logging.getLogger().debug('VideoReceiverSFP: mfd frames are being recorded but no MFD callbacks are registered')
                            except Exception:
                                pass
                except Exception:
                    pass

                for mcb in list(getattr(module, '_mfd_callbacks', [])):
                    try:
                        mcb(frame)
                    except Exception:
                        pass
            except Exception:
                pass

        # generic callbacks and saving
        for cb in list(getattr(module, '_callbacks', [])):
            try:
                if getattr(module, '_save_png', False) and Image is not None and hasattr(frame, 'save'):
                    try:
                        if getattr(module, '_dump_manager', None) is not None:
                            saved = module._dump_manager.save_preview_from_pil(frame, category='frame', fmt='png')
                            if saved:
                                logging.getLogger().info("VideoReceiverSFP: saved frame to %s", saved)
                        else:
                            ts = time.strftime('%Y%m%d_%H%M%S') + (f"_{int(time.time() * 1000) % 1000:03d}")
                            dumps_dir = getattr(module, '_dumps_dir', os.path.join(os.getcwd(), 'dumps'))
                            os.makedirs(dumps_dir, exist_ok=True)
                            pngpath = os.path.join(dumps_dir, f'VideoReceiverSFP_frame_{ts}.png')
                            frame.save(pngpath)
                            module._saved_pngs.append(pngpath)
                            while len(module._saved_pngs) > module._dump_keep:
                                old = module._saved_pngs.popleft()
                                try:
                                    pathlib.Path(old).unlink()
                                except Exception:
                                    pass
                    except Exception:
                        logging.getLogger().exception('VideoReceiverSFP: failed to save preview png')
                try:
                    cb(frame)
                except Exception:
                    pass
            except Exception:
                pass
    except Exception:
        logging.getLogger().exception('VideoReceiverSFP: dispatch_frame unexpected error')
