#include "MysqlClient.h"
#include "common/Utils.h"
#include "Spdlogger.h"
#include <chrono>
using namespace std;

static int64_t GetTimestamp()
{
	return chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
}

MysqlClient::MysqlClient(MysqlOption option) : option(option)
{
	conn();
}

MysqlClient::~MysqlClient()
{
	this->close();
}

static int64_t g_tickErr {0};

int MysqlClient::conn()
{
	if (mysql_)
	{
		return 0;
	}
	if (GetTimestamp() - g_tickErr <= 10)
	{ 
		return 1; 
	}
	mysql_ = mysql_init(nullptr);
	MYSQL* ret = mysql_real_connect(mysql_, 
		option.host.c_str(), 
		option.user.c_str(), 
		option.password.c_str(), 
		option.dbname.c_str(), 
		option.port, NULL, 0);
	if (ret == NULL)
	{
		std::string err = mysql_error(mysql_);
		//Spdlogger::info("[mysql] connect failed: {}", mysql_error(mysql_));
		mysql_ = nullptr;
		g_tickErr = GetTimestamp();
	}
	else
	{
		g_tickErr = 0;
		mysql_query(mysql_, "set names 'utf8';");
	}
	return 0;
}

bool MysqlClient::isConnected()
{
	return (mysql_ != nullptr);
}

void MysqlClient::close()
{
	if (mysql_)
	{
		mysql_close(mysql_);
		mysql_ = nullptr;
	}
}

static int MysqlQuery(MYSQL* mysql, const std::string& sql)
{
	int err = 0;
	if (!mysql)
	{
		spdlog::error("Mysql exec error, database is not connected.");
		return err;
	}
	if (sql.empty())
	{
		spdlog::error("Mysql exec error, sql is empty.");
		return err;
	}
	err = mysql_query(mysql, sql.c_str());
	if (0 != err)
	{
		err = mysql_errno(mysql);
		spdlog::error("Mysql exec error: {}, {}, sql={}", err, mysql_error(mysql), sql);
		return err;
	}
	return err;
}

int MysqlClient::exec(std::string sql)
{
	if (!mysql_) return 1;
	int err = MysqlQuery(mysql_, sql);
	// 确保读取并释放结果集，否则会产生 [2014,Commands out of sync;] 错误
	MYSQL_RES* res = mysql_store_result(mysql_);
	if (res) { mysql_free_result(res); }
	return err;
}

int MysqlClient::exec(std::string sql, vector<Fields>& result)
{
	if (!mysql_) { return 1; }
	result.clear();
	int err = MysqlQuery(mysql_, sql);
	if (err != 0)
	{
		return err;
	}

	MYSQL_RES* res = mysql_store_result(mysql_);
	if (res)
	{
		vector<string> fieldNames;
		while (true)
		{
			MYSQL_FIELD* field = mysql_fetch_field(res);
			if (!field)
			{
				break;
			}
			fieldNames.push_back(field->name);
		}

		while (true)
		{
			MYSQL_ROW row = mysql_fetch_row(res);
			if (!row)
			{
				break;
			}

			Fields rowData;
			for (size_t i = 0; i < fieldNames.size(); ++i)
			{
				string field_text = (row[i] == NULL) ? "" : row[i];
				rowData.set(fieldNames[i], field_text);
			}
			result.push_back(rowData);
		}

		// 释放结果集
		mysql_free_result(res);
	}
	return 0;
}