#include "opmysql.h"
#include <algorithm>
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/exception.h>
#include <hv/hlog.h>
#include <hv/md5.h>
#include <sstream>  
#include "openjson.h"

OpDatabase OpDatabase::m_instance;

OpDatabase::OpDatabase()
	:m_pDbConnection(nullptr)
{
}

OpDatabase::~OpDatabase()
{
	//CloseDatabase();
}


std::string OpDatabase::CalculateMD5(const std::string& data)
{
	char md5_str[33] = { 0 };
	hv_md5_hex((unsigned char*)data.c_str(), data.size(), md5_str, 33);

	std::string smd5(md5_str);
	std::transform(smd5.begin(), smd5.end(), smd5.begin(),
		[](unsigned char c)
		{
			return std::toupper(c);
		});
	return smd5;
}

OpDatabase* OpDatabase::getInstance()
{
	return &m_instance;
}

bool OpDatabase::OpenDatabase(const std::string& server, const std::string& dbuser, const std::string& database)
{
	// 打开数据库
	try
	{
		// 数据库连接配置
		//std::string server = "tcp://127.0.0.1:3306";
		//std::string dbuser = "root";
		std::string password = "Hj57471000";
		//std::string database = "hjems";

		// 创建连接
		sql::mysql::MySQL_Driver* driver;
		driver = sql::mysql::get_mysql_driver_instance();
		//m_pDbConnection.reset(driver->connect(server, dbuser, password));
		m_pDbConnection = driver->connect(server, dbuser, password);

		if (!m_pDbConnection)
		{
			hloge("Failed to connect to database.");
			return false;
		}

		// 设置为使用指定数据库
		m_pDbConnection->setSchema(database);

		return true;
	}
	catch (sql::SQLException& e)
	{
		std::ostringstream ss;
		ss << "SQLException: " << e.what();
		ss<< " (MySQL error code: " << e.getErrorCode();
		ss << ", SQLState: " << e.getSQLState() << " )";
		hloge("Failed to connect to database: %s",ss.str().c_str());
		return false;
	}
}

// 关闭数据库连接
void OpDatabase::CloseDatabase()
{
	m_pDbConnection->close();
	//delete m_pDbConnection;
}


void OpDatabase::InsertMessage(const std::string& ts, const std::string& msg_type, const std::string& fsu, const std::string& content, int topic, int dev_id)
{
	const char* insertSql = "INSERT INTO tbl_data (data_timestamp, data_type, FsuCode, data_content, topic, device_id) VALUES (?,?,?,?,?,?);";
	// 创建预编译的prepared statement
	std::unique_ptr<sql::PreparedStatement> insertStmt(m_pDbConnection->prepareStatement(insertSql));

	// 绑定插入数据的参数
	insertStmt->setString(1, ts);
	insertStmt->setString(2, msg_type);
	insertStmt->setString(3, fsu);
	insertStmt->setString(4, content);
	insertStmt->setInt(5, topic);
	insertStmt->setInt(6, dev_id);

	// 执行插入操作
	int rowsAffected = insertStmt->executeUpdate();

	// 检查插入操作是否成功
	if (rowsAffected > 0)
	{
		hlogi( "New message inserted successfully." );
	}
	else
	{
		hloge( "No rows affected during insert operation." );
	}
}

bool OpDatabase::queryUser(const std::string& user_id, const std::string& passwd_md5, std::string& jsonResult)
{
	try
	{
#if 0
		// 数据库连接配置
		std::string server = "tcp://127.0.0.1:3306";
		std::string dbuser = "root";
		std::string password = "Hj57471000";
		std::string database = "hjems";

		// 创建连接
		sql::mysql::MySQL_Driver* driver;
		driver = sql::mysql::get_mysql_driver_instance();
		//m_pDbConnection.reset(driver->connect(server, dbuser, password));
		sql::Connection* pDbConnection = driver->connect(server, dbuser, password);

		if (!pDbConnection)
		{
			hloge("Failed to connect to database.");
			return false;
		}

		// 设置为使用指定数据库
		pDbConnection->setSchema(database);
		hloge("%s : %s", user_id.c_str(), passwd_md5.c_str());
#endif
		// 准备SQL查询语句
		std::string sql = "SELECT uid,uname, upasswd,usalt,email,mobile1,mobile2,memo FROM tbl_user WHERE uid = ?";

		// 创建预编译的prepared statement
		std::unique_ptr<sql::PreparedStatement> pstmt(m_pDbConnection->prepareStatement(sql));

		// 绑定参数
		pstmt->setString(1, user_id); // 替换为你要查询的用户名

		// 执行查询
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
		
		bool ret = false;
		OpenJson json;
		auto& nodeRoot = json["user"];

		int i = 0;

		// 处理结果集
		while (res->next())
		{
			auto& node = nodeRoot[i++];
			node["valid"] = 0;
			node["uid"] = res->getString("uid");

			// 假设username和password都是字符串类型
			std::string pass = res->getString("upasswd");
			std::string salt = res->getString("usalt");

			//计算passwd和salt之间的关系
			//!passwd=md5(passwd_md5+salt+salt)
			// passwd_md5 是大写的,需要确保一下
			std::string tmp2(passwd_md5);
			std::transform(tmp2.begin(), tmp2.end(), tmp2.begin(),
				[](unsigned char c)
				{
					return std::toupper(c);
				});

			std::string tmp = tmp2 + salt + salt;
			std::string smd5 = CalculateMD5(tmp);

			if (pass == smd5)
			{
				node["valid"] = 1;
				
				node["uname"] = res->getString("uname");
				node["email"] = res->getString("email");
				node["mobile1"] = res->getString("mobile1");
				node["mobile2"] = res->getString("mobile2");
				node["memo"] = res->getString("memo");
			
				ret = true;
				break;
			}
			else
			{
				hloge("upass=[%s],calc=[%s],src=[%s]", pass.c_str(), smd5.c_str(), tmp.c_str());
			}
		}

		jsonResult = json.encode();

		//pDbConnection->close();
		//delete pDbConnection;

		return ret;
	}
	catch (sql::SQLException& e)
	{
		std::ostringstream ss;
		ss << "SQLException: " << e.what();
		ss << " (MySQL error code: " << e.getErrorCode();
		ss << ", SQLState: " << e.getSQLState() << " )";
		hloge("Failed to connect to database: %s", ss.str().c_str());
		return false;
	}
}


bool OpDatabase::queryInnerDevice(int dev_id, std::string& jsonResult)
{
	try
	{
#if 0
		// 数据库连接配置
		std::string server = "tcp://127.0.0.1:3306";
		std::string dbuser = "root";
		std::string password = "Hj57471000";
		std::string database = "hjems";

		// 创建连接
		sql::mysql::MySQL_Driver* driver;
		driver = sql::mysql::get_mysql_driver_instance();
		//m_pDbConnection.reset(driver->connect(server, dbuser, password));
		sql::Connection* pDbConnection = driver->connect(server, dbuser, password);

		if( !pDbConnection )
		{
			hloge("Failed to connect to database.");
			return false;
		}

		// 设置为使用指定数据库
		pDbConnection->setSchema(database);
		hloge("%s : %s", user_id.c_str(), passwd_md5.c_str());
#endif
		// 准备SQL查询语句
		std::string sql = "SELECT uid,uname, upasswd,usalt,email,mobile1,mobile2,memo FROM tbl_user WHERE uid = ?";

		// 创建预编译的prepared statement
		std::unique_ptr<sql::PreparedStatement> pstmt(m_pDbConnection->prepareStatement(sql));

		// 绑定参数
		pstmt->setString(1, user_id); // 替换为你要查询的用户名

		// 执行查询
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		bool ret = false;
		OpenJson json;
		auto& nodeRoot = json["user"];

		int i = 0;

		// 处理结果集
		while( res->next() )
		{
			auto& node = nodeRoot[i++];
			node["valid"] = 0;
			node["uid"] = res->getString("uid");

			// 假设username和password都是字符串类型
			std::string pass = res->getString("upasswd");
			std::string salt = res->getString("usalt");

			//计算passwd和salt之间的关系
			//!passwd=md5(passwd_md5+salt+salt)
			// passwd_md5 是大写的,需要确保一下
			std::string tmp2(passwd_md5);
			std::transform(tmp2.begin(), tmp2.end(), tmp2.begin(),
				[](unsigned char c)
				{
					return std::toupper(c);
				});

			std::string tmp = tmp2 + salt + salt;
			std::string smd5 = CalculateMD5(tmp);

			if( pass == smd5 )
			{
				node["valid"] = 1;

				node["uname"] = res->getString("uname");
				node["email"] = res->getString("email");
				node["mobile1"] = res->getString("mobile1");
				node["mobile2"] = res->getString("mobile2");
				node["memo"] = res->getString("memo");

				ret = true;
				break;
			}
			else
			{
				hloge("upass=[%s],calc=[%s],src=[%s]", pass.c_str(), smd5.c_str(), tmp.c_str());
			}
		}

		jsonResult = json.encode();

		//pDbConnection->close();
		//delete pDbConnection;

		return ret;
	}
	catch( sql::SQLException& e )
	{
		std::ostringstream ss;
		ss << "SQLException: " << e.what();
		ss << " (MySQL error code: " << e.getErrorCode();
		ss << ", SQLState: " << e.getSQLState() << " )";
		hloge("Failed to connect to database: %s", ss.str().c_str());
		return false;
	}
}