#pragma once

#include "types.h"

namespace lt {

// GET /
struct Agent {
    std::string version = "";
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Agent, version)

// GET /:board
struct Board {
    std::string model = "";
    unsigned int sn = 0;
    unsigned int cpu = 0;
    unsigned int fpga = 0;
    unsigned int bridge = 0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Board, model, sn, cpu, fpga, bridge)

//
struct AudioSignal {
    std::string description = "";
    std::string format = "";
    std::string signal = "";
    int channels = 0;
    int samplerate = 0;
    int depth = 0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioSignal, description, format, signal, channels, samplerate, depth)

struct VideoSignal {
    std::string description = "";
    std::string format = "";
    std::string signal = "";
    std::array<int, 2> size = {};
    double framerate = 0;
    bool interlaced = false;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VideoSignal, description, format, signal, size, framerate, interlaced)

// GET /:board/:input/:id
struct Input {
    AudioSignal audio = {};
    VideoSignal video = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Input, audio, video)

// GET,POST /:board/:input/:id/edid
struct Edid {
    std::vector<char> data = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Edid, data)

// GET,POST /:board/:output/:id
struct Output {
    std::string source = "";
    std::string overlay = "";
    std::string overlayMode = "";
    std::string format = "";
    std::string link = "";

    AudioSignal audio = {};
    VideoSignal video = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Output, source, overlay, overlayMode, format, link, audio, video)

//
// Create DataWorker (POST)
//

struct AudioDataWorker {
    std::string media;

    // Format
    int channels = 0;
    int samplerate = 0;
    int depth = 0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioDataWorker, media, channels, samplerate, depth)

struct ImageDataWorker {
    std::string media;

    // Format
    std::array<int, 2> size = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ImageDataWorker, media, size)

struct VideoDataWorker {
    std::string media;

    // Format
    std::array<int, 2> size = {};
    double framerate = 0.0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VideoDataWorker, media, size, framerate)

//
// Create FileWorker (POST)
//

struct AudioFileWorker {
    std::string media;

    // File
    std::string location;
    int64_t duration = 0;
    int splitSize = 0;
    int64_t splitDuration = 0;

    // Format
    int channels = 0;
    int samplerate = 0;
    int depth = 0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioFileWorker, media, location, duration, splitSize, splitDuration, channels, samplerate, depth)

struct ImageFileWorker {
    std::string media;

    // File
    std::string location;

    // Format
    std::array<int, 2> size = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ImageFileWorker, media, location, size)

struct VideoEncoderExtra {
    // Encoder
    std::string hw = "";

    //
    int bitrate = 0;
    int quality = 0;
    int gop = 0;

    // Codec
    std::string codec = "";

    // Preset
    std::string preset = "";
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VideoEncoderExtra, hw, bitrate, quality, gop, codec, preset)

struct VideoFileWorker {
    std::string media;

    // File
    std::string location;
    int64_t duration = 0;
    int splitSize = 0;
    int64_t splitDuration = 0;

    // Format
    std::array<int, 2> size = {};
    double framerate = 0.0;

    // Extra parameters
    VideoEncoderExtra extra = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VideoFileWorker, media, location, duration, splitSize, splitDuration, size, framerate)

// Packet metadata
struct AudioMetadata {
    int channels = 0;
    int samplerate = 0;
    int depth = 0;
    int samples = 0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AudioMetadata, channels, samplerate, depth, samples)

struct ImageMetadata {
    std::array<int, 2> size = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ImageMetadata, size)

struct VideoMetadata {
    std::array<int, 2> size = {};
    double framerate = 0.0;
    bool interlaced = false;
    bool keyframe = false;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(VideoMetadata, size, framerate, interlaced, keyframe)

//
// Canvas
//

struct CanvasOps {
    std::vector<json> ops;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasOps, ops)

// POST /canvas/:id/init
struct CanvasInit {
    std::string op = "init";

    std::string source = "";

    std::array<int, 4> color = {};
    std::array<int, 2> size = {};
    double framerate = 0.0;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasInit, op, source, color, size, framerate)

// POST /canvas/:id/clear
struct CanvasClear {
    std::string op = "clear";

    std::array<int, 4> color = {};
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    int thickness = 0;
    std::string source = "";
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasClear, op, color, position, size, thickness, source)

// POST /canvas/:id/text
struct CanvasText {
    std::string op = "text";

    std::string text = "";
    std::string align = "";

    // Shape
    std::string font = "";
    int fontSize = 0;
    bool italic = false;
    bool bold = false;
    std::array<int, 4> color = {};
    std::array<int, 4> background= {};

    // Container
    double angle = 0.0;
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasText, op, text, align, font, fontSize, italic, bold, color, background, angle, position, size, anchor)

// POST /canvas/:id/line
struct CanvasLine {
    std::string op = "line";

    // Shape
    int width = 0;
    std::array<int, 4> color = {};
    std::vector<int> pattern;

    // Container
    double angle = 0.0;
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasLine, op, width, color, pattern, angle, position, size, anchor)

// POST /canvas/:id/ellipse
struct CanvasEllipse {
    std::string op = "ellipse";

    // Shape
    int width = 0;
    std::array<int, 4> color = {};
    std::array<int, 4> fill = {};
    std::vector<int> pattern;

    // Container
    double angle = 0.0;
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasEllipse, op, width, color, fill, pattern, angle, position, size, anchor)

// POST /canvas/:id/rectangle
struct CanvasRectangle {
    std::string op = "rectangle";

    // Shape
    int width = 0;
    std::array<int, 4> color = {};
    std::array<int, 4> fill = {};
    std::vector<int> pattern;
    int rounded = 0;

    // Container
    double angle = 0.0;
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasRectangle, op, width, color, fill, pattern, rounded, angle, position, size, anchor)

// POST /canvas/:id/image
struct CanvasImage {
    std::string op = "image";

    // Source
    std::string source = "";

    // Data
    std::string format = "";
    int width = 0;
    int height = 0;
    std::vector<char> data;

    // Container
    double angle = 0.0;
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasImage, op, source, format, width, height, data, angle, position, size, anchor)

// POST /canvas/:id/video
struct CanvasVideo {
    std::string op = "video";

    // Source
    std::string source = "";

    // Container
    std::array<int, 2> position = {};
    std::array<int, 2> size = {};
    std::array<double , 2> anchor = {};
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(CanvasVideo, op, source, position, size, anchor)

} // namespace lt