/*
 * https://webfolder.io/license.html
 */
package io.webfolder.cdp.video;

import static io.webfolder.cdp.JsonLibrary.Jackson;
import static io.webfolder.cdp.event.Events.PageScreencastFrame;
import static io.webfolder.cdp.logger.CdpLoggerType.Console;
import static io.webfolder.cdp.logger.CdpLogggerLevel.Info;
import static java.awt.Desktop.getDesktop;
import static java.awt.Desktop.isDesktopSupported;
import static java.util.EnumSet.of;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static java.util.concurrent.TimeUnit.SECONDS;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

import io.webfolder.cdp.Example;
import io.webfolder.cdp.Launcher;
import io.webfolder.cdp.Options;
import io.webfolder.cdp.session.Session;
import io.webfolder.cdp.session.SessionFactory;
import io.webfolder.cdp.session.VideoRecorder;
import io.webfolder.cdp.session.VideoRecorderOptions;
import io.webfolder.cdp.session.VideoRecorderResult;

//
// Record video and encode with vp8 encoder
// this example uses embedded ffmpeg executable
//
// Please make sure to add io.webfolder:ffmpeg-executable:1.1.0 to your project's pom.xml
//
// @see https://github.com/webfolderio/ffmpeg-executable
//
@Example
public class VideoRecorderExample {

    private static VideoRecorder recorder;

    private static ExecutorService encoderThreadPool;

    public static void main(String[] args) {
        Launcher launcher = new Launcher(Options.builder()
                                                .loggerType(Console)
                                                .consoleLoggerLevel(Info)
                                                .jsonLibrary(Jackson)
                                            .build());

        // cdp4j supports both sync and async video encoding
        // use your encoding mode based on your requirements
        boolean encodeSync = false;

        CompletableFuture<VideoRecorderResult> videoRecorderResult = null;

        // By default VideoRecorder uses Java common pool by default
        // If you will encode video with encodeAsync()
        // you might optional set your own thread pool for ffmpeg process
        if ( !encodeSync ) {
            encoderThreadPool = newSingleThreadExecutor();
        }

        try (SessionFactory factory = launcher.launch();
                            Session session = factory.create()) {

            session.setRegisteredEventListeners(of(PageScreencastFrame));

            recorder = session.createVideoRecoder(
                // All options are optional
                VideoRecorderOptions.builder()
                                    .encodingTimeout(60, SECONDS) // default value is 30 seconds (ffmpeg process timeout)
                                    .encoderThreadPool(encoderThreadPool)
                                .build()
            );

            recorder.start();

            session
                .navigate("https://webkit.org/blog-files/3d-transforms/poster-circle.html")
                .waitDocumentReady()
                .wait(5_000);

            session.navigate("https://yahoo.com");
            for (int i = 0; i < 50; i++) {
                session.wait(100);
                session.evaluate("window.scrollBy(0,10)");
            }

            recorder.stop();

            if (encodeSync) {
                // sync video encoding (blocks current/session thread)
                VideoRecorderResult result = recorder.encode();
                if (result.isSucceess() && isDesktopSupported()) {
                    try {
                        getDesktop().open(result.getVideoFile().toFile());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            } else {
                // async video encoding
                videoRecorderResult = recorder.encodeAsync();
            }
        }

        // it's better to prefer use async encoder instead of sync
        // no need to keep Session open, video encoder hasn't direct dependency to Session
        if ( ! encodeSync && videoRecorderResult != null ) {
            try {
                VideoRecorderResult result = videoRecorderResult.get();
                if (result.isSucceess() && isDesktopSupported()) {
                    try {
                        getDesktop().open(result.getVideoFile().toFile());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }

        if ( encoderThreadPool != null ) {
            encoderThreadPool.shutdownNow();
        }
    }
}