#pragma once

//major minor patch
#define LITTLESNITCH_VERSION 100

#include <iostream>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>

#include <qdebug.h>

#include <nlohmann/json.hpp>

using json = nlohmann::json;

template<typename T, typename K>
bool json_get(json j, T& value, K key) noexcept {
    try {
        j[key].get_to(value);
        return true;
    } catch (nlohmann::detail::type_error& err) {
        std::cout << "key " << key << " error " << err.what();
    } catch (nlohmann::detail::out_of_range& err) {
        std::cout << "key " << key << " error " << err.what();
    } catch (nlohmann::detail::other_error& err) {
        std::cout << "key " << key << " error " << err.what();
    }
    return false;
}

template<typename T, typename K, typename... Ks>
bool json_get(json j, T& value, K key, Ks... keys) noexcept {
    try {
        return json_get(j[key], value, keys...);
    } catch (nlohmann::detail::type_error& err) {
        std::cout << "key " << key << " error " << err.what();
    } catch (nlohmann::detail::out_of_range& err) {
        std::cout << "key " << key << " error " << err.what();
    } catch (nlohmann::detail::other_error& err) {
        std::cout << "key " << key << " error " << err.what();
    }
    return false;
}


//! represents one item in the http history.
struct HistoryItem {
    int id = -1;
    double timestamp = 0;
    std::string method;
    std::string scheme;
    std::string host;
    unsigned short port = 0;
    std::string path;
    int status_code = 0;
    std::string reason;
    double rtt = 0.0;
    size_t size = 0;
    std::string request_http_version;
    std::map<std::string, std::string> request_headers;
    std::string request_content;
    std::string response_http_version;
    std::map<std::string, std::string> response_headers;
    std::string response_content;
};

namespace http {

struct Request
{
    std::string server_ip_address;

    bool tls;
    std::string content;
    std::string scheme;
    std::string method;
    std::string host;
    unsigned short port;
    std::string http_version;
    std::string path;
    double timestamp_start;
    double timestamp_end;
    std::vector<std::tuple<std::string,std::string>> headers;

    std::string error;

};

struct Response {
    int status_code;
    std::string http_version;
    std::string reason;
    std::string content;
    double timestamp_start;
    double timestamp_end;
    std::vector<std::tuple<std::string,std::string>> headers;
};

struct Flow {
    std::string uid;
    Request request;
    Response response;
};

}