import threading
import time
import cv2
import inspect
import vp_module as vp

#
# vp.VP_SET_LOG_INCLUDE_THREAD_ID(False)
# vp.VP_SET_LOG_LEVEL(vp.LogLevel.DEBUG)
# vp.VP_LOGGER_INIT()


print("vp_module:", vp.__doc__)


def debug_info(message=""):
    frame = inspect.currentframe().f_back
    function_name = frame.f_code.co_name
    line_number = frame.f_lineno
    print(f"info: {function_name}, {line_number} - {message}")


class UsbCamNode(vp.vp_node):
    def __init__(self, nodde_name, cam_id,  callback=None, mode=vp.QueueMode.DropOldest):
        super().__init__(nodde_name, mode)
        self.initialized()
        self.cam_id = cam_id
        self.width = 640
        self.height = 480
        self.fps = 30
        self.channel_index = 0
        self.frame_index = 0
        self.callback = callback
        # self.gst_template = f"v4l2src device=/dev/video{cam_id} ! video/x-raw,format=YUY2,width={self.width},height={self.height} ! videoconvert !  video/x-raw,format=BGR ! appsink";
        self.gst_template = cam_id
        self.cap = None
        self.video_source = f"filesrc location={cam_id} ! qtdemux ! h264parse ! avdec_h264 ! videoconvert ! appsink"
        self.cap_lock = threading.Lock()

    def stop_cap(self):
        self.alive = False
        self.gate_open()
        with self.cap_lock:
            if self.cap is not None:
                self.cap.release()
                self.cap = None

    def handle_run(self):
        with self.cap_lock:
            if self.alive:
                self.cap = cv2.VideoCapture(1)
                print("[Python] VideoCapture initialized.")
        while self.alive:
            self.gate_knock()
            if not self.cap.isOpened():
                print(f"[{self.video_source}] Unable to open video source, retrying...")
                time.sleep(1)
                if self.alive:
                    with self.cap_lock:
                        try:
                            self.cap = cv2.VideoCapture(1)
                            print("[Python] VideoCapture reopened.")
                        except AttributeError as e:
                            print(f"Exception in handle_run: {e}")
                            break
                else:
                    print("[Python] alive is False, not reopening.")
                    break
                continue
            stream_info = vp.vp_stream_info(self.channel_index, self.fps, self.width, self.height, self.name)
            self.invoke_stream_info_hooker(self.name, stream_info)
            try:
                with self.cap_lock:
                    if self.cap is not None:
                        ret, frame = self.cap.read()
                    else:
                        ret = False
                        frame = None
                if not ret:
                    print(f"[{self.video_source}] Unable to read frame.")
                    if self.cycle:
                        print("Cycling to the beginning of the video.")
                        with self.cap_lock:
                            if self.cap is not None:
                                self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
                    else:
                        time.sleep(1)
                    break
            except cv2.error as e:
                print(f"OpenCV error while reading frame: {e}")
                break
            except Exception as e:
                print(f"General error: {e}")
                break
            if not self.alive:
                print("[Python] alive is False, breaking loop.")
                break
            if frame is not None:
                self.width = frame.shape[1]
                self.height = frame.shape[0]
                self.frame_index += 1
                if self.callback:
                    self.callback(frame, None)
                out_meta = vp.vp_frame_meta(frame, self.frame_index, 0, self.width, self.height, self.fps)
                self.push_meta(out_meta)
        print("[Python] ----------------->handle_run exit.")
        self.push_meta(None)
        print("handle_run exit.")

    def handle_old_run(self):
        self.cap = cv2.VideoCapture(1)
        while self.alive:
            self.gate_knock()
            stream_info = vp.vp_stream_info(self.channel_index, self.fps, self.width, self.height, self.name)
            self.invoke_stream_info_hooker(self.name, stream_info)
            ret, frame = self.cap.read()
            if not ret:
                print(f"[{self.gst_template}] Unable to read frame.")
                time.sleep(1)
                continue
            self.width = frame.shape[1]
            self.height = frame.shape[0]
            self.frame_index += 1
            if self.callback:
                self.callback(frame, None)
            out_meta = vp.vp_frame_meta(frame, self.frame_index, 0, self.width, self.height, self.fps)
            self.push_meta(out_meta)
        if self.cap is not None:
            self.cap.release()
        self.push_meta(None)         