#include "AppData.h"
#include "common/Utils.h"
#include "app/Station.h"
#include "app/Device.h"
#include "app/Policy.h"
#include "database/Dao.h"
#include "common/JsonN.h"
#include "common/Snowflake.h"
#include "common/Spdlogger.h"
#include "protocol/MqttEntity.h"

void ElectPeriod::parse(std::string jsonstr)
{
    njson jsonroot;
    JSON::parse(jsonstr, jsonroot);

    JSON::read(jsonroot, "price_super_peak", this->priceSuperPeak);
    JSON::read(jsonroot, "price_peak", this->pricePeak);
    JSON::read(jsonroot, "price_shoulder", this->priceShoulder);
    JSON::read(jsonroot, "price_off_peak", this->priceOffPeak);
    JSON::read<std::vector<std::vector<std::string>>>(jsonroot, "periods", this->vecPeriods);
}

std::string ElectPeriod::dump()
{
    njson jsonroot;
    jsonroot["price_super_peak"] = this->priceSuperPeak;
    jsonroot["price_peak"] = this->pricePeak;
    jsonroot["price_shoulder"] = this->priceShoulder;
    jsonroot["price_off_peak"] = this->priceOffPeak;
    jsonroot["periods"] = this->vecPeriods;
    return jsonroot.dump();
}


bool AppData::initFromDB()
{
    auto dao = DaoEntity::create("");
    if (!dao->isConnected())
    {
        spdlog::error("Init app data failed, database connected error.");
        return false;
    }

    std::string str;
    std::vector<Fields> result;

    { // 数据库读取工作模式定义
        str = "", result.clear();
        DAO::queryWorkModeDef(dao, result);
        this->mapping.workMode.clear();
        for (auto& fields: result)
        {
            int workModeId = fields.get<int>(DMDefWorkMode::WORK_MODE_ID);
            std::string name = fields.value(DMDefWorkMode::NAME);
            this->mapping.workMode.push_back({std::to_string(workModeId), name});
            this->mapWorkMode[workModeId] = name;
            str += ("工作模式: {" + std::to_string(workModeId)+":" + name + "},");
        }
        spdlog::info(str);
    }
    { // 数据库读取策略类型定义
        str = "", result.clear();
        DAO::queryPolicyTypeDef(dao, result);
        this->mapping.policyType.clear();
        for (auto& fields: result)
        {
            int policyTypeId = fields.get<int>(DMDefPolicyType::POLICY_TYPE_ID);
            std::string name = fields.value(DMDefWorkMode::NAME);
            this->mapping.policyType.push_back({std::to_string(policyTypeId), name});
            this->mapPolicyType[policyTypeId] = name;
            //str += ("策略类型: {" + std::to_string(policyTypeId) + ":" + name + "},");
        }
        //spdlog::info(str);
    }
    { // 数据库读取设备类型定义
        str = "", result.clear();
        DAO::queryDeviceTypeDef(dao, result);
        mapping.deviceType.clear();
        for (auto& fields: result)
        {
            auto item = std::make_shared<DeviceType>();
            item->typeId = fields.get<int>(DMDefDeviceType::DEVICE_TYPE_ID);
            item->name = fields.value(DMDefDeviceType::NAME);
            item->group = fields.value(DMDefDeviceType::GROUP);
            item->attr = fields.value(DMDefDeviceType::ATTRS);
            item->fieldsAttr.parseJson(item->attr);
            mapDeviceType[item->typeId] = item;
            mapping.deviceType.push_back({std::to_string(item->typeId), item->name});
            //str += ("设备类型: {" + std::to_string(item->typeId) + ":" + item->name + "},");
        }
        //spdlog::info(str);
    }
    { // 数据库读取角色定义
        str = "", result.clear();
        DAO::queryRoleList(dao, result);
        this->mapping.role.clear();
        for (auto& fields : result)
        {
            auto item = std::make_shared<Role>();
            item->roleId = fields.get<int>(DMRole::ROLE_ID);
            item->name = fields.value(DMRole::NAME);
            item->isOpen = fields.get<int>(DMRole::IS_OPEN);
            mapRole[item->roleId] = item;
            mapping.role.push_back({std::to_string(item->roleId), item->name});
            //str += ("角色: {" + std::to_string(item->roleId) + ":" + item->name + "},");
        }
        //spdlog::info(str);
    }
    { // 数据库读取场站信息
        str = "", result.clear();
        std::string sql = "SELECT s.*, p.name policy_name, p.`type` policy_type, p.value FROM station s LEFT JOIN policy p ON s.policy_id=p.policy_id;";
        dao->exec(sql, result);
        this->mapping.stationName.clear();
        for (auto& fields: result)
        {
            auto station = std::make_shared<Station>();
            station->setFields(fields);
            this->mapStation[station->stationId] = station;
            this->mapping.stationName.push_back({std::to_string(station->stationId), station->name});
            spdlog::info("场站: {}:{}, {}", station->stationId, station->name, station->status>0 ? "启用" : "未启用");
        }
    }
    { // 数据库读取设备信息
        str = "", result.clear();
        DAO::queryDeviceList(dao, result, 1);
        for (auto& fields: result)
        {
            int deviceId = fields.get<int>(DMDevice::DEVICE_ID);
            int stationId = fields.get<int>(DMDevice::STATION_ID);
            auto station = this->getStation(stationId);
            if (station)
            {
                station->addDevice(fields);
            }
            else
            {
                spdlog::error("init device error: unknown station_id:, device_id=",  stationId, deviceId);
            }
        }
        for (auto& item : mapStation)
        {
            item.second->groupDevice();
        }
    }
    { // 数据库读取策略信息
        str = "", result.clear();
        DAO::queryPolicyList(dao, result);
        for (auto& fields: result)
        {
            auto policy = std::make_shared<SysPolicy>();
            policy->setFields(fields);
            this->mapPolicy[policy->policyId] = policy;
        }
    }
    { // 数据库读取电价分段信息
        //result.clear();
        //vecElectPeriods.resize(12);
        //DAO::exec(dao, "SELECT * FROM configure;", result);
        //
        //Fields info;
        //for (auto& fields: result)
        //{
        //    auto k = fields.value("key");
        //    auto v = fields.value("val");
        //    info.set(k, v);
        //}

        //for (int month = 1; month<=12; month++)
        //{
        //    if (month-1 < vecElectPeriods.size())
        //    {
        //        auto& vecItems = vecElectPeriods[month-1];
        //        std::string str = info.value("period_" + std::to_string(month));
        //        std::vector<std::string> vec;
        //        Utils::split(str, ",", vecItems);
        //    }
        //}
        //electPriceSuperPeak = info.get<double>("price_super_peak");
        //electPricePeak = info.get<double>("price_peak");
        //electPriceShoulder = info.get<double>("price_shoulder");
        //electPriceOffPeak = info.get<double>("price_off_peak");
    }
    { // 数据库读取统计数据
        vector<Fields> result;
        std::string curDate = Utils::dateStr();
        DAO::queryStatDataList(dao, curDate, curDate, result);
        for (auto& fields: result)
        {
            std::string dt = fields.value(DMStatStation::DT);
            int stationId = fields.get<int>(DMStatStation::STATION_ID);
            auto station = this->getStation(stationId);
            if (station)
            {
                //station->storageIn = fields.get<double>(DMStatStation::STORAGE_ELECT_IN);
                //station->storageOut = fields.get<double>(DMStatStation::STORAGE_ELECT_OUT);
                //station->storageNumIn = fields.getFloat(DMStatStation::STORAGE_NUM);
                //station->storageNumOut = fields.getFloat(DMStatStation::STORAGE_NUM);
                //station->storageNumErr = fields.get<int>(DMStatStation::STORAGE_NUM_ERR);
                //station->solarGen = fields.get<double>(DMStatStation::SOLAR_ELECT_GEN);
                //station->solarGrid = fields.get<double>(DMStatStation::SOLAR_ELECT_GRID);
                //station->solarNumErr = fields.get<int>(DMStatStation::SOLAR_NUM_ERR);
                //station->chargeElect = fields.get<double>(DMStatStation::CHARGE_ELECT);
                //station->chargeNum = fields.get<int>(DMStatStation::CHARGE_NUM);
                //station->chargeNumErr = fields.get<int>(DMStatStation::CHARGE_NUM_ERR);
            }
            else
            {
                spdlog::error("init staticis data error: unknown station_id:{}, dt={}", stationId, dt);
            }
        }
    }

    { // 初始化场站设备的历史监测数据（当天）
        vector<Fields> result;
        DAO::queryRuntimeDataHistory(dao, Utils::dateStr(), result);
        for (auto& item : result)
        {
            int stationId = item.get<int>("station_id");
            int deviceId = item.get<int>("device_id");
            int datatype = item.get<int>("datatype");
            auto device = this->getDevice(stationId, deviceId);
            if (device)
            {
                std::string value = item.value("value");
                std::vector<float> vd;
                JSON::parseArray(value, vd);
                device->setCache(datatype, vd);
            }
        }
    }
    { // 初始化预测数据源的历史数据（当天）
        vector<Fields> result;
        DAO::queryPredictHistory(dao, Utils::dateStr(), result);
        for (auto& item : result)
        {
            int stationId = item.get<int>("station_id");
            int datatype = item.get<int>("datatype");
            auto station = this->getStation(stationId);
            if (station)
            {
                std::string value = item.value("value");
                std::vector<float> vd;
                JSON::parseArray(value, vd);
                station->setCache(datatype, vd);
            }
        }
    }
    return true;
}

bool AppData::init()
{
    bool ret = this->initFromDB();
    if (!ret) { return false; }


    this->launchDate = Config::option.lunchDate;
    return true;
}

std::shared_ptr<Station> AppData::getStation(int stationId)
{
    auto iter = mapStation.find(stationId);
    if (iter!=mapStation.end())
    {
        return iter->second;
    }
    return nullptr;
}
int AppData::getStationCount()
{
    return mapStation.size();
}

std::shared_ptr<Station> AppData::getStationByName(std::string name)
{
    for (auto iter = mapStation.begin(); iter!=mapStation.end(); ++iter)
    {
        if (iter->second->name == name)
        {
            return iter->second;
        }
    }
    return nullptr;
}

std::shared_ptr<Station> AppData::getStationByCode(std::string code)
{
    for (auto iter = mapStation.begin(); iter!=mapStation.end(); ++iter)
    {
        if (iter->second->code == code)
        {
            return iter->second;
        }
    }
    return nullptr;
}

std::shared_ptr<Device> AppData::getDevice(int stationId, int deviceId)
{
    auto station = getStation(stationId);
    if (station)
    {
        return station->getDevice(deviceId);
    }
    return nullptr;
}

std::shared_ptr<Device> AppData::getDeviceByType(int stationId, int deviceType, std::string code)
{
    auto station = getStation(stationId);
    if (station)
    {
        return station->getDeviceByType(deviceType, code);
    }
    return nullptr;
}

std::string AppData::getDeviceNameById(int typeId)
{
    auto iter = mapDeviceType.find(typeId);
    if (iter != mapDeviceType.end())
    {
        return iter->second->name;
    }
    return "";
}

std::shared_ptr<DeviceType> AppData::getDeviceTypeDef(int typeId)
{
    auto iter = mapDeviceType.find(typeId);
    if (iter != mapDeviceType.end())
    {
        return iter->second;
    }
    return nullptr;
}

void AppData::loadStatData()
{
}

static std::map<std::string, User> g_mapUser;
std::string AppData::userLogin(std::string userId, std::string account)
{
    for (auto iter = g_mapUser.begin(); iter!=g_mapUser.end(); ++iter)
    {
        if (iter->second.userId == userId) // 重复登录
        {
            g_mapUser.erase(iter);
            break;
        }
    }
    User user;
    user.userId = userId;
    user.account = account;
    user.loginTime = Utils::time();
    user.token = Snowflake::instance().getIdStr();
    g_mapUser[user.token] = user;
    return user.token;
}
User AppData::getUser(std::string token)
{
    auto iter = g_mapUser.find(token);
    if (iter != g_mapUser.end()) 
    { 
        return iter->second; 
    }
    return User();
}


int AppData::getWorkModeIdByName(std::string  name)
{
    for (auto iter = mapWorkMode.begin(); iter!=mapWorkMode.end(); ++iter)
    {
        if (iter->second == name)
        {
            return iter->first;
        }
    }
    return 0;
}

std::vector<std::string> AppData::getRoleNames()
{
    std::vector<std::string> vec(mapRole.size());
    int i = 0;
    for (auto iter = mapRole.begin(); iter!=mapRole.end(); ++iter)
    {
        vec[i] = iter->second->name;
        ++i;
    }
    return vec;
}

std::vector<std::string> AppData::getStationNames()
{
    std::vector<std::string> vec(mapStation.size());
    int i = 0;
    for (auto iter = mapStation.begin(); iter!=mapStation.end(); ++iter)
    {
        vec[i] = iter->second->name;
        ++i;
    }
    return vec;
}

std::vector<std::string> AppData::getDeviceTypeNames()
{
    std::vector<std::string> vec(mapping.deviceType.size());
    int i = 0;
    for (auto iter = mapping.deviceType.begin(); iter!=mapping.deviceType.end(); ++iter)
    {
        vec[i] = iter->second;
        ++i;
    }
    return vec;
}

std::vector<std::string> AppData::getWorkModes()
{
    std::vector<std::string> vec(mapWorkMode.size());
    int i = 0;
    for (auto iter = mapWorkMode.begin(); iter!=mapWorkMode.end(); ++iter)
    {
        vec[i] = iter->second;
        ++i;
    }
    return vec;
}

std::vector<std::string> AppData::getPolicyTypeNames()
{
    std::vector<std::string> vec(mapPolicyType.size());
    int i = 0;
    for (auto iter = mapPolicyType.begin(); iter!=mapPolicyType.end(); ++iter)
    {
        vec[i] = iter->second;
        ++i;
    }
    return vec;
}

std::vector<std::string> AppData::getPolicyNames()
{
    std::vector<std::string> vec;
    return vec;
}

std::shared_ptr<SysPolicy> AppData::getPolicyByType(int typeId)
{
    for (auto iter = mapPolicy.begin(); iter != mapPolicy.end(); ++iter)
    {
        if (iter->second->type == typeId) { return iter->second; }
    }
    return nullptr;
}

std::shared_ptr<SysPolicy> AppData::getPolicyById(int policyId)
{
    auto iter = mapPolicy.find(policyId);
    if (iter != mapPolicy.end())
    {
        return iter->second;
    }
    return nullptr;
}


//std::vector<std::string> AppData::getElectPreiodVals(int month)
//{
//    if (month > 0 && month-1 < vecElectPeriods.size())
//    {
//        return vecElectPeriods[month-1];
//    }
//    return {};
//}
//
//std::string AppData::getElectPreiodVal(int month, int hour)
//{
//    if (month > 0 && month-1 < vecElectPeriods.size())
//    {
//        auto& vec = vecElectPeriods[month-1];
//        if (hour > 0 && hour-1 < vec.size())
//        {
//            auto& val = vec[hour-1];
//            if (val == "尖") return "尖峰";
//            if (val == "峰") return "高峰";
//            if (val == "平") return "平段";
//            if (val == "谷") return "低谷";
//            return val;
//        }
//    }
//    return "";
//}

void AppData::storeRuntimeDB()
{
    auto t = Utils::date();

    std::string valStr;
    for (auto iter=mapDataDay.begin(); iter!=mapDataDay.end(); ++iter)
    {
        auto& v = iter->second;
        if (v != 0.0)
        {
            if (!valStr.empty()) valStr += ",";
            valStr += ("[" + std::to_string(iter->first) + "," + Utils::toStr(v, 2) + "]");
        }
    }
    valStr = "[" + valStr + "]";
    Fields fields;
    fields.set("dt", Utils::dateStr(t));
    fields.set("device_id", 1);
    fields.set("datatype", 1);
    fields.set("value", valStr);
    DAO::insertRuntimeData(NULL, fields);
}