/*
 * Example: Record video from an LT device input
 *
 * This example demonstrates how to:
 *      1. Connect to a given input source on an LT device.
 *      2. Verify that the source has a locked video signal.
 *      3. Create a worker to record the input in MP4 format.
 *      4. Save the recording to the current working directory.
 *      5. Capture keyboard events to control the recording:
 *         - space key : start/pause recording
 *         - any other key : stop recording
 *
 * The recording is configured for a total duration of 20 seconds with file splits every 6 seconds.
 *
 * Usage:
 *      record.exe -source <sourceURL>
 *
 * Arguments:
 *      -source, -s   URL of a valid LT input, for example:
 *                        lt310:/0/hdmi-in/0
 *                        lt310:/0/sdi-in/1
 *
 * Note:
 *      This code is intended for demonstration purposes. For production use,
 *      ensure proper error handling and resource cleanup.
 *
 * © 2025 Enciris Technologies. All rights reserved.
 */

#include "../../lt.h"
#include "keyboard.hpp"

#include <iostream>

#ifdef _WIN32
#include <direct.h>
#define GET_CURDIR _getcwd
#else
#include <unistd.h>
#define GET_CURDIR getcwd
#endif

void printHelp() {
    std::cout << R"(
Usage:
    record.exe -source <sourceURL>

Arguments:
    -source, -s   URL of a valid LT input (e.g. lt310:/0/sdi-in/0)

This example records video from the selected input and saves it as an MP4 file
in the current working directory.
)" << std::endl;
}

/**
 * Fatal error handler - logs message and exits application cleanly.
 */
auto logFatal = [](const std::string& msg) -> void {
    throw std::runtime_error("\nFATAL ERROR: " + msg);
};

/**
 * Main application entry point.
 */
int main(int argc, char** argv)
{
    // Print command line usage if no arguments provided
    if (argc < 2) {
        printHelp();
        return 1;
    }

    try {
        lt::Client client;
        lt::error err;

        // Parse command line options
        std::string sourceURL;

        for (int i = 1; i < argc; i++) {
            if ((strcmp(argv[i], "-source") == 0 || strcmp(argv[i], "-s") == 0) && i + 1 < argc) {
                sourceURL = argv[++i];
            }
        }

        // Require source URL
        if (sourceURL.empty()) {
            printHelp();
            return 1;
        }

        // -------------------------------------------------------------------------
        // Check if input selected is active
        // -------------------------------------------------------------------------
        lt::Input input;

        err = client.Get(sourceURL, input);
        if (!err.empty()) {
            logFatal("Failed to get input: " + err);
        }

        if (input.video.signal != "locked") {
            logFatal("Input source is not locked");
        }

        // -------------------------------------------------------------------------
        // Starts recording
        // -------------------------------------------------------------------------

        // Select an absolute path to a capture directory
        char buffer[1024];
        std::string wd = std::string(GET_CURDIR(buffer, sizeof(buffer))); // Current working directory

        // Create worker
        err = client.Post(sourceURL + "/file", lt::VideoFileWorker{ "video/mp4", wd , 20 , 0 , 6 }, nullptr);
        if (!lt::ErrorIs(err, lt::ErrRedirect)) {
            logFatal("worker creation failed:" + err);
        }
        std::string workerURL = lt::RedirectLocation(err);

        // -------------------------------------------------------------------------
        // Capture keyboard events
        //   - space key : start/pause recording
        //   - any other key : stop recording
        // -------------------------------------------------------------------------
        Keyboard keyboard;
        std::cout << "Press SPACE to start/pause recording, any other key to stop.\n" << std::endl;

        // -------------------------------------------------------------------------
        // Main loop
        //  - process keyboard events
        //  - monitor recording status
        // -------------------------------------------------------------------------
        bool paused = false;
        int recordSize = 0;

        for (int i = 0;; i++) {
            // Check for keyboard event (non-blocking)
            char c;
            if (keyboard.getEvent(c)) {
                if (c == ' ') {
                    // Start/pause recording
                    if (paused) {
                        err = client.Post(workerURL + "/start", nullptr, nullptr);
                        if (!err.empty()) {
                            logFatal("failed to start recording: " + err);
                        }
                        paused = false;
                    }
                    else {
                        err = client.Post(workerURL + "/pause", nullptr, nullptr);
                        if (!err.empty()) {
                            logFatal("failed to pause recording: " + err);
                        }
                        paused = true;
                    }
                }
                else {
                    // Stop recording
                    err = client.Post(workerURL + "/stop", nullptr, nullptr);
                    if (!err.empty()) {
                        logFatal("failed to stop recording: " + err);
                    }
                    std::cout << "\nRecording stopped by user." << std::endl;
                }
            }

            // Fetch worker response
            lt::Worker worker;
            err = client.Get(workerURL, worker);
            if (!err.empty()) {
                if (lt::ErrorIs(err, lt::ErrEOF)) {
                    break; // worker finished
                }
                logFatal(err);
            }

            // Process all packets (display only video packet info)
            for (auto& packet : worker->packets) {
                auto type = packet->media.substr(0, packet->media.find("/"));
                if (type == "video") {
                    lt::VideoMetadata meta = packet->meta.template get<lt::VideoMetadata>();
                    std::cout << "\r" << worker->name << " " << meta.size[0] << "x" << meta.size[1] << " " << worker->length - recordSize << " bytes";

                }
            }

			// When status is "completed", the current file is closed (either due to split or worker stopped)
			// Save the total recording size and print a new line for the next file
            if (worker->status == "completed") {
                recordSize = worker->length;
                std::cout << "\n";
            }
        }

        std::cout << "\nRecording saved successfully." << std::endl;
        return 0;
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}