#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <tuple>
#include <utility>
#include <vector>

class Streamer {
public:
    struct StreamInfo {
        std::string sourceAddress_;
        std::string destinationAddress_;
        uint16_t sourcePort_;
        uint16_t destinationPort_;
        uint16_t vlan_;

        bool operator==(const StreamInfo& other) const {
            return std::tie(sourceAddress_, destinationAddress_, sourcePort_, destinationPort_, vlan_) ==
                   std::tie(other.sourceAddress_, other.destinationAddress_, other.sourcePort_, other.destinationPort_, other.vlan_);
        }
    };

    virtual ~Streamer() = default;
    Streamer(const Streamer&) = default;
    Streamer(Streamer&&) = default;
    Streamer& operator=(const Streamer&) = default;
    Streamer& operator=(Streamer&&) = default;

    Streamer(const std::vector<StreamInfo>& info)
        : info_(info) {}

    virtual bool addReceiver(const StreamInfo& info) = 0;
    virtual bool removeReceiver(const StreamInfo& info) = 0;
    virtual bool addData(const std::vector<uint8_t>& data) = 0;
    virtual bool validateData(const std::vector<uint8_t>& data) const = 0;
    virtual bool startStream() = 0;
    virtual bool stopStream() = 0;
    virtual bool streamInProgress() const = 0;

private:
    std::vector<StreamInfo> info_;
};

// Create two classes and add some dummy implementations to allow check if code works :)

int main() {
    // Testing Mpeg2Streamer
    std::unique_ptr<Streamer> streamer = std::make_unique<Mpeg2Streamer>(
        Streamer::StreamInfo{"192.168.0.0", "192.168.10.24", 5432, 5432, 12});

    std::cout << std::boolalpha << streamer->addData({1, 2, 3, 4, 5, 6, 7}) << '\n';
    std::cout << streamer->startStream() << '\n';
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << '\n'
              << streamer->stopStream() << '\n';
    std::cout << std::boolalpha << streamer->addData({1, 2, 3, 4, 5, 6}) << '\n';

    // Testing MjpegStreamer
    streamer = std::make_unique<MjpegStreamer>(
        Streamer::StreamInfo{"192.168.0.0", "192.168.10.24", 5432, 5432, 12});

    // true
    std::cout << std::boolalpha << streamer->addData({1, 2, 3, 4, 5, 6}) << '\n';
    std::cout << streamer->startStream() << '\n';
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << '\n'
              << streamer->stopStream() << '\n';
    std::cout << std::boolalpha << streamer->addData({1, 2, 3, 4, 5, 6, 7}) << '\n';
}