import cv2

class VideoProcessing:
    """@brief A class for loading, reading, and managing video streams using OpenCV.

    @details
    This class provides basic functionality for working with video files:
    - Loading a video from a file path.
    - Reading frames sequentially.
    - Releasing system resources after use.

    It is designed for modular integration with image-processing workflows, 
    enabling real-time or frame-by-frame analysis from video inputs.
    """

    def __init__(self, video_path=None):
        """@brief Initialize the VideoProcessing object.

        @details
        Optionally takes a video file path at initialization. If provided, 
        the constructor automatically loads the video for reading.

        @param video_path (optional) The file path to the video file to load.
        """
        self.cap = None
        if video_path:
            self.load_video(video_path)

    def load_video(self, video_path):
        """@brief Load a video file for processing.

        @details
        Opens a video file using OpenCV’s `VideoCapture`. If another video is 
        already loaded, it is safely released before opening the new one.

        @param video_path The file path to the video file to load.

        @throws ValueError If the video cannot be opened successfully.
        """
        if self.cap is not None:
            self.cap.release()

        self.cap = cv2.VideoCapture(video_path)

        if not self.cap.isOpened():
            raise ValueError(f"Cannot open video file: {video_path}")

    def get_next_frame(self):
        """@brief Retrieve the next frame from the video stream.

        @details
        Reads the next available frame from the video. If the end of the video
        is reached or the video is not properly loaded, returns `None`.

        @return The next video frame as a NumPy array, or `None` if no frame is available.

        @throws RuntimeError If no video is loaded before calling this function.
        """
        if self.cap is None:
            raise RuntimeError("No video loaded. Call load_video() first.")

        ret, frame = self.cap.read()
        if not ret:
            return None  # End of video or error

        return frame

    def release(self):
        """@brief Release the video capture resource.

        @details
        Safely releases the OpenCV `VideoCapture` object to free up system resources.
        This should always be called when video processing is complete.
        """
        if self.cap is not None:
            self.cap.release()
            self.cap = None
