"""TODO : Doc String."""
import argparse
import os
from pathlib import Path

import cv2
import numpy as np
import pyarrow as pa
from dora import Node
from ffmpeg import FFmpeg


def main():
    """Handle dynamic nodes, ask for the name of the node in the dataflow."""
    parser = argparse.ArgumentParser(
        description="Video Encoder: This node is used to record episodes of a robot interacting with the environment.",
    )

    parser.add_argument(
        "--name",
        type=str,
        required=False,
        help="The name of the node in the dataflow.",
        default="video_encoder",
    )

    if not os.getenv("VIDEO_NAME") or not os.getenv("FPS"):
        raise ValueError("Please set the VIDEO_NAME and FPS environment variables.")

    video_name = os.getenv("VIDEO_NAME")
    fps = int(os.getenv("FPS"))

    args = parser.parse_args()

    node = Node(args.name)

    recording = False
    episode_index = 1

    dataflow_id = node.dataflow_id()

    base = Path("out") / dataflow_id / "videos"
    out_dir = base / f"{video_name}_episode_{episode_index:06d}"
    name = f"{video_name}_episode_{episode_index:06d}.mp4"

    if not out_dir.exists():
        out_dir.mkdir(parents=True)

    # We initialize the output canal with a first data
    node.send_output(
        "image",
        pa.array([{"path": f"videos/{name}", "timestamp": float(0) / fps}]),
    )

    frame_count = 0
    for event in node:
        event_type = event["type"]

        if event_type == "INPUT":
            event_id = event["id"]

            if event_id == "image":
                if recording:
                    base = Path("out") / dataflow_id / "videos"
                    out_dir = base / f"{video_name}_episode_{episode_index:06d}"
                    name = f"{video_name}_episode_{episode_index:06d}.mp4"

                    if not out_dir.exists():
                        out_dir.mkdir(parents=True)

                    node.send_output(
                        "image",
                        pa.array(
                            [
                                {
                                    "path": f"videos/{name}",
                                    "timestamp": float(frame_count) / fps,
                                },
                            ],
                        ),
                        event["metadata"],
                    )

                    arrow_image = event["value"][0]
                    image = {
                        "width": arrow_image["width"].as_py(),
                        "height": arrow_image["height"].as_py(),
                        "channels": arrow_image["channels"].as_py(),
                        "data": arrow_image["data"].values.to_numpy().astype(np.uint8),
                    }

                    data = image["data"].reshape(
                        (image["height"], image["width"], image["channels"]),
                    )

                    path = str(out_dir / f"frame_{frame_count:06d}.png")
                    cv2.imwrite(path, data)

                    frame_count += 1

            elif event_id == "episode_index":
                episode = event["value"][0].as_py()
                recording = episode != -1

                if recording:
                    episode_index = episode
                else:
                    # save all the frames into a video
                    base = Path("out") / dataflow_id / "videos"
                    out_dir = base / f"{video_name}_episode_{episode_index:06d}"
                    name = f"{video_name}_episode_{episode_index:06d}.mp4"
                    video_path = base / name

                    ffmpeg = (
                        FFmpeg()
                        .option("y")
                        .input(str(out_dir / "frame_%06d.png"), f="image2", r=fps)
                        .output(
                            str(video_path), vcodec="libx264", g=2, pix_fmt="yuv444p",
                        )
                    )

                    ffmpeg.execute()

                    frame_count = 0

        elif event_type == "ERROR":
            raise ValueError("An error occurred in the dataflow: " + event["error"])


if __name__ == "__main__":
    main()
