#pragma once


struct ClashProxySpeedHistory
{
	// Date time; // FIXME
	uint32_t delay;

	friend void from_json(const nlohmann::json& j, ClashProxySpeedHistory& value) {
		JSON_FROM(delay);
	}
};



struct ClashProxy
{
	using Name = std::string; // UTF-8

	enum struct Type
	{
		Unknown,
		URLTest,
		Fallback,
		LoadBalance,
		Selector,
		Direct,
		Reject,
		Shadowsocks,
		ShadowsocksR,
		Socks5,
		Http,
		Vmess,
		Snell,
		Trojan,
		Relay,
	};

	Name name;
	Type type = Type::Unknown;
	std::vector<Name> all;
	std::vector<ClashProxySpeedHistory> history;
	std::optional<Name> now;

	friend void from_json(const nlohmann::json& j, ClashProxy& value) {
		JSON_FROM(name);
		JSON_FROM(type);
		JSON_TRY_FROM(all);
		JSON_FROM(history);
		try { value.now.emplace(j.at("now").get<decltype(now)::value_type>()); }
		catch (...) {}
	}
};

NLOHMANN_JSON_SERIALIZE_ENUM(ClashProxy::Type, {
	{ClashProxy::Type::Unknown, nullptr},
	{ClashProxy::Type::URLTest, "URLTest"},
	{ClashProxy::Type::Fallback, "Fallback"},
	{ClashProxy::Type::LoadBalance, "LoadBalance"},
	{ClashProxy::Type::Selector, "Selector"},
	{ClashProxy::Type::Direct, "Direct"},
	{ClashProxy::Type::Reject, "Reject"},
	{ClashProxy::Type::Shadowsocks, "Shadowsocks"},
	{ClashProxy::Type::ShadowsocksR, "ShadowsocksR"},
	{ClashProxy::Type::Socks5, "Socks5"},
	{ClashProxy::Type::Http, "Http"},
	{ClashProxy::Type::Vmess, "Vmess"},
	{ClashProxy::Type::Snell, "Snell"},
	{ClashProxy::Type::Trojan, "Trojan"},
	{ClashProxy::Type::Relay, "Relay"},
	});

struct ClashProxies
{
	using MapType = std::unordered_map<ClashProxy::Name, ClashProxy>;

	MapType proxies;

	friend void from_json(const nlohmann::json& j, ClashProxies& value) {
		JSON_FROM(proxies);
	}
};

ClashProxies g_clashProxies;

struct ClashProvider
{
	using Name = std::string; // UTF-8

	enum struct Type
	{
		Unknown,
		Proxy,
		String,
	};

	enum struct VehicleType
	{
		Unknown,
		HTTP,
		File,
		Compatible,
	};

	Name name;
	std::vector<ClashProxy> proxies;
	Type type;
	VehicleType vehicleType;
};

NLOHMANN_JSON_SERIALIZE_ENUM(ClashProvider::Type, {
	{ClashProvider::Type::Unknown, nullptr},
	{ClashProvider::Type::Proxy, "Proxy"},
	{ClashProvider::Type::String, "String"},
	});

NLOHMANN_JSON_SERIALIZE_ENUM(ClashProvider::VehicleType, {
	{ClashProvider::VehicleType::Unknown, nullptr},
	{ClashProvider::VehicleType::HTTP, "HTTP"},
	{ClashProvider::VehicleType::File, "File"},
	{ClashProvider::VehicleType::Compatible, "Compatible"},
	});

struct ClashProviders
{
	std::map<ClashProvider::Name, ClashProvider> providers;

	/*friend void from_json(const json& j, ClashProviders& value) {
		JSON_FROM(providers);
	}*/
};

enum struct ClashProxyMode
{
	Unknown,
	Global,
	Rule,
	Direct
};

NLOHMANN_JSON_SERIALIZE_ENUM(ClashProxyMode, {
	{ClashProxyMode::Unknown, nullptr},
	{ClashProxyMode::Global, "global"},
	{ClashProxyMode::Rule, "rule"},
	{ClashProxyMode::Direct, "direct"},
	})

	enum struct ClashLogLevel
{
	Unknown,
	Error,
	Warning,
	Info,
	Debug,
	Silent
};

NLOHMANN_JSON_SERIALIZE_ENUM(ClashLogLevel, {
	{ClashLogLevel::Unknown, nullptr},
	{ClashLogLevel::Error, "error"},
	{ClashLogLevel::Warning, "warning"},
	{ClashLogLevel::Info, "info"},
	{ClashLogLevel::Debug, "debug"},
	{ClashLogLevel::Silent, "silent"},
	}
)


struct ClashConfig
{
	uint16_t port;
	uint16_t socksPort;
	uint16_t mixedPort;
	bool allowLan;
	ClashProxyMode mode;
	ClashLogLevel logLevel;

	friend void from_json(const nlohmann::json& j, ClashConfig& c) {
		j.at("port").get_to(c.port);
		j.at("socks-port").get_to(c.socksPort);
		j.at("mixed-port").get_to(c.mixedPort);
		j.at("allow-lan").get_to(c.allowLan);
		j.at("mode").get_to(c.mode);
		j.at("log-level").get_to(c.logLevel);
	}
};