"""This example script demonstrates how to use the library to record and display the frames acquired by a personal
webcam. It is intentionally kept minimalistic.
See API documentation at https://ataraxis-video-system-api-docs.netlify.app/ for additional configuration options
exposed by VideoSystem interface.
See https://github.com/Sun-Lab-NBB/ataraxis-video-system?tab=readme-ov-file#usage for more details on how to use this
library.
Authors: Ivan Kondratyev (Inkaros), Jacob Groner (Jgroner11), Natalie Yeung
"""

from pathlib import Path

import numpy as np
from ataraxis_time import PrecisionTimer
from ataraxis_data_structures import DataLogger

from ataraxis_video_system import VideoSystem, InputPixelFormats

# Since most classes used in this example use multiprocessing, they have to run inside the __main__ guard
if __name__ == "__main__":
    # The directory where to output the recorded frames and the acquisition timestamps
    output_directory = Path("/home/cybermouse/Desktop/vid_test")

    # The DataLogger is used to save frame acquisition timestamps to disk. During runtime, it logs frame timestamps as
    # uncompressed NumPy arrays (.npy), and after runtime it can compress log entries into one .npz archive.
    logger = DataLogger(output_directory=output_directory, instance_name="webcam", exist_ok=True)

    # DataLogger uses a parallel process to write log entries to disk. It has to be started before it can save any log
    # entries.
    logger.start()

    # The VideoSystem minimally requires an ID and a DataLogger instance. The ID is critical, as it is used to identify
    # the log entries generated by the VideoSystem. For VideoSystems that will be saving frames, output_directory is
    # also required
    vs = VideoSystem(system_id=np.uint8(101), data_logger=logger, output_directory=output_directory)

    # By default, all added cameras are interfaced with using OpenCV backend. Check the API documentation to learn about
    # all available camera configuration options and supported backends. This camera is configured to save frames and to
    # display the live video feed to the user at 25 fps. The display framerate can be the same or lower as the
    # acquisition framerate.
    vs.add_camera(
        save_frames=True,
        acquisition_frame_rate=30,
        display_frames=True,
        display_frame_rate=15,
        color=False,  # Acquires images in MONOCHROME mode
    )

    # To save the frames acquired by the system, we need to add a saver. Here, we demonstrate adding a video saver, but
    # you can also use the add_image_saver() method to output frames as images. The default video saver uses CPU and
    # H265 codec to encode frames as an MP4 video.
    vs.add_video_saver(input_pixel_format=InputPixelFormats.MONOCHROME)

    # Calling this method arms the video system and starts frame acquisition. However, the frames are not initially
    # saved to disk.
    vs.start()

    timer = PrecisionTimer("s")
    timer.delay_noblock(delay=2)  # During this delay, camera frames are displayed to the user but are not saved

    # Begins saving frames to disk as an MP4 video file
    vs.start_frame_saving()
    timer.delay_noblock(delay=5)  # Records frames for 5 seconds, generating ~150 frames
    vs.stop_frame_saving()

    # Frame acquisition can be started and stopped as needed, although all frames will be written to the same output
    # video file. If you intend to cycle frame acquisition, it may be better to use an image saver backend.

    # Stops the VideoSystem runtime and releases all resources
    vs.stop()

    # Stops the DataLogger and compresses acquired logs into a single .npz archive. This step is required for being
    # able to parse the data with the VideoSystem API
    logger.stop()
    logger.compress_logs(remove_sources=True)

    # Extracts the list of frame timestamps from the compressed log generated above. The extraction function
    # automatically uses VideoSystem ID, DataLogger name, and the output_directory to resolve the archive path.
    timestamps = vs.extract_logged_data()  # Returns a list of timestamps, each is given in microseconds since epoch
    # onset

    # Computes and prints the actual framerate of the camera based on saved frames.
    timestamp_array = np.array(timestamps, dtype=np.uint64)
    time_diffs = np.diff(timestamp_array)
    fps = 1 / (np.mean(time_diffs) / 1e6)
    print(fps)

    # You can also check the output directory for the created video.
