#include "DaoEntity.h"
//#include "PvInstance.h"
//#include "spdlogger.h"

MysqlOption DaoEntity::option;

DaoEntity::DaoEntity(string tb_name)
{
    //MysqlOptions opts;
    //opts.host = "localhost";
    //opts.user = "root";
    //opts.password = "123456";
    //opts.port = 3306;
    //opts.dbname = "pvb";
    db = make_shared<MysqlClient>(DaoEntity::option);
    if (!db->isConnected())
    {
        //Global::data().status_msg = "数据库连接异常！";
        //PvInstance::send_user_event(nullptr, EUserEvent::ALARM_DB, "数据库连接异常！");
    }
    tableName = tb_name;
}

DaoEntity::~DaoEntity()
{
    db = nullptr;
}

MysqlOption& DaoEntity::mysqlOption()
{
    return DaoEntity::option;
}
void DaoEntity::setOption(std::string host, int port, std::string user, std::string pwd, std::string dbname)
{
    option.host = host;
    option.port = port;
    option.user = user;
    option.password = pwd;
    option.dbname = dbname;
}

std::shared_ptr<DaoEntity> DaoEntity::create(string tb_name)
{
    return std::make_shared<DaoEntity>(tb_name);
}

int DaoEntity::execOnce(string sql)
{
    auto db = make_shared<MysqlClient>(DaoEntity::option);
    return db->exec(sql);
}

int DaoEntity::execOnce(string sql, vector<Fields>& result)
{
    auto db = make_shared<MysqlClient>(DaoEntity::option);
    return db->exec(sql, result);
}

void DaoEntity::setTableName(string tb_name)
{
    tableName = tb_name;
}

bool DaoEntity::isConnected()
{
    return db->isConnected();
}

int DaoEntity::exec(string sql)
{
    return db->exec(sql);
}

int DaoEntity::exec(string sql, vector<Fields>& result)
{
    return db->exec(sql, result);
}

int DaoEntity::insertFields(Fields& fields)
{
    string sql = fields.toSqlInsert(tableName);
    return this->db->exec(sql);
}

int DaoEntity::insertFields(vector<Fields>& vec_fields)
{
    //"insert into TABLE () values ()";
    string sql = "insert into " + tableName;
    bool first = true;
    string keys;
    string values;

    for (auto& field : vec_fields)
    {
        keys = "";
        values = "";
        for (auto& item : field.map())
        {
            const string& k = item.first;
            const string& v = item.second;
            if (first)
            {
                if (!keys.empty()) { keys += ","; }
                keys += k;
            }
            if (!values.empty()) { values += ","; }
            values += ("'" + v + "'");
            std::cout << k << std::endl;
        }
        if (first)
        {
            sql += (" (" + keys + ")");
            sql += (" values (" + values + ")");
            first = !first;
        }
        else
        {
            sql += (",(" + values + ")");
        }
    }
    sql += ";";
    return this->db->exec(sql);
}

int DaoEntity::duplicateUpdate(Fields& fields, const vector<string>& keys)
{
    //insert into device_attr(device_id, attr_id, attr_val) values('26', 'model', '型号1') on duplicate key update attr_val='型号1';
    string key;
    string val;
    for (auto& item : fields.map())
    {
        if (!key.empty()) { key += ","; val += ","; }
        key += (item.first);
        val += ("'" + item.second + "'");
    }
    string str;
    for (auto& k : keys)
    {
        if (fields.contains(k))
        {
            if (!str.empty()) { str += ","; }
            str += (k + "='" + fields.value(k) + "'");
        }
    }
    string sql = "INSERT INTO " + tableName + "(" + key + ") VALUES (" + val + ") ON duplicate KEY UPDATE " + str;
    return this->db->exec(sql);
}

//void DaoEntity::queryFields(const string& condition, DaoPageinfo& pageinfo, vector<map<string, string>>& result)
//{
//	this->query_by_page(condition, pageinfo, [&](map<string, string>& row) mutable {
//		result.push_back(row);
//	});
//}

int DaoEntity::queryFields(string keys, const string& condition, vector<Fields>& result)
{
    ostringstream oss;
    oss << "SELECT " + keys + " FROM " << tableName << (" " + condition) << "; ";
    return this->db->exec(oss.str(), result);
}

int DaoEntity::queryFields(string keys, const string& condition, PageInfo& page, vector<Fields>& result)
{
    int err = 0;
    ostringstream oss;
    oss << "SELECT count(1) total FROM `" << tableName << "` " << condition << ";";

    vector<Fields> res_total;
    if (err = this->db->exec(oss.str().c_str(), res_total))
    {
        return err;
    }

    if (res_total.size() <= 0)
    {
        page.total = 0;
        return err;
    }
    page.total = res_total[0].get<int>("total");
    if (page.total <= 0)
    {
        return err;
    }

    oss.str("");
    if (page.index <= 0) { page.index = 1; }
    int start = (page.index - 1) * page.size;
    oss << "SELECT " << keys << " FROM `" << tableName << "` " << condition << " LIMIT " << start << "," << page.size << ";";
    return this->db->exec(oss.str().c_str(), result);
}

int DaoEntity::updateFields(Fields& fields, const string& condition)
{
    string sql = fields.toSqlUpdate(tableName, condition);
    return this->db->exec(sql);
}

int DaoEntity::updateFields(Fields& fields, vector<string> vecKeys, const string& condition)
{
    string sql = fields.toSqlUpdate(tableName, vecKeys, condition);
    return this->db->exec(sql);
}