const system = require("../system");
class Dao {
  constructor(modelName) {
    this.modelName = modelName;
    var db = system.getObject("db.common.connection").getCon();
    this.db = db;
    console.log("........set dao model..........");
    console.log(this.modelName)
    this.model = db.models[this.modelName];
    console.log(this.modelName);
  }
  preCreate (u) {
    return u;
  }
  async create (u, t) {
    var u2 = this.preCreate(u);
    if (t) {
      console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
      console.log(this.model);
      return this.model.create(u2, { transaction: t }).then(u => {
        return u;
      });
    } else {
      return this.model.create(u2).then(u => {
        return u;
      });
    }
  }
  static getModelName (ClassObj) {
    return ClassObj["name"].substring(0, ClassObj["name"].lastIndexOf("Dao")).toLowerCase()
  }
  async refQuery (qobj) {
    var w = qobj.refwhere ? qobj.refwhere : {};
    if (qobj.levelinfo) {
      w[qobj.levelinfo.levelfield] = qobj.levelinfo.level;
    }
    if (qobj.parentinfo) {
      w[qobj.parentinfo.parentfield] = qobj.parentinfo.parentcode;
    }
    //如果需要控制数据权限
    if (qobj.datapriv) {
      w["id"] = { [this.db.Op.in]: qobj.datapriv };
    }
    if (qobj.likestr) {
      w[qobj.fields[0]] = { [this.db.Op.like]: "%" + qobj.likestr + "%" };
      return this.model.findAll({ where: w, attributes: qobj.fields });
    } else {
      return this.model.findAll({ where: w, attributes: qobj.fields });
    }
  }
  async bulkDelete (ids, t) {
    if (t) {
      var en = await this.model.destroy({ where: { id: { [this.db.Op.in]: ids } }, transaction: t });
      return en;
    } else {
      var en = await this.model.destroy({ where: { id: { [this.db.Op.in]: ids } } });
      return en
    }

  }
  async bulkDeleteByWhere (whereParam, t) {
    var en = null;
    if (t != null && t != 'undefined') {
      whereParam.transaction = t;
      return await this.model.destroy(whereParam);
    } else {
      return await this.model.destroy(whereParam);
    }
  }
  async delete (qobj, t) {
    var en = null
    if (t != null && t != 'undefined') {
      en = await this.model.findOne({ where: { id: qobj.id }, transaction: t });
      if (en != null) {
        await en.destroy({ transaction: t });
        return en
      }
    } else {
      en = await this.model.findOne({ where: { id: qobj.id } });
      if (en != null) {
        return en.destroy();
      }
    }
    return null;
  }
  extraModelFilter (pobj) {
    //return {"key":"include","value":{model:this.db.models.app}};
    return null;
  }
  extraWhere (obj, where) {
    return where;
  }
  orderBy (qobj) {
    //return {"key":"include","value":{model:this.db.models.app}};
    if (!qobj.orderInfo || qobj.orderInfo.length == 0) {
      return [["created_at", "DESC"]];
    } else {
      return qobj.orderInfo;
    }

  }
  buildQuery (qobj) {
    var linkAttrs = [];
    const pageNo = qobj.pageInfo.pageNo;
    const pageSize = qobj.pageInfo.pageSize;
    const search = qobj.search;
    var qc = {};
    //设置分页查询条件
    qc.limit = pageSize;
    qc.offset = (pageNo - 1) * pageSize;
    //默认的查询排序
    qc.order = this.orderBy(qobj);
    //构造where条件
    qc.where = {};
    if (search) {
      Object.keys(search).forEach(k => {
        console.log(search[k], ":search[k]search[k]search[k]");
        if (search[k] && search[k] != 'undefined' && search[k] != "") {
          if ((k.indexOf("Date") >= 0 || k.indexOf("_at") >= 0)) {
            if (search[k] != "" && search[k]) {
              var stdate = new Date(search[k][0]);
              var enddate = new Date(search[k][1]);
              qc.where[k] = { [this.db.Op.between]: [stdate, enddate] };
            }
          }
          else if (k.indexOf("id") >= 0) {
            qc.where[k] = search[k];
          }
          else if (k.indexOf("channelCode") >= 0) {
            qc.where[k] = search[k];
          }
          else if (k.indexOf("Type") >= 0) {
            qc.where[k] = search[k];
          }
          else if (k.indexOf("Status") >= 0) {
            qc.where[k] = search[k];
          }
          else if (k.indexOf("status") >= 0) {
            qc.where[k] = search[k];
          }
          else {
            if (k.indexOf("~") >= 0) {
              linkAttrs.push(k);
            } else {
              qc.where[k] = { [this.db.Op.like]: "%" + search[k] + "%" };
            }
          }
        }
      });
    }
    this.extraWhere(qobj, qc.where, qc, linkAttrs);
    var extraFilter = this.extraModelFilter(qobj);
    if (extraFilter) {
      qc[extraFilter.key] = extraFilter.value;
    }
    console.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm");
    console.log(qc);
    return qc;
  }
  buildaggs (qobj) {
    var aggsinfos = [];
    if (qobj.aggsinfo) {
      qobj.aggsinfo.sum.forEach(aggitem => {
        var t1 = [this.db.fn('SUM', this.db.col(aggitem.field)), aggitem.field + "~" + "sum"];
        aggsinfos.push(t1);
      });
      qobj.aggsinfo.avg.forEach(aggitem => {
        var t2 = [this.db.fn('AVG', this.db.col(aggitem.field)), aggitem.field + "~" + "avg"];
        aggsinfos.push(t2);
      });
    }
    return aggsinfos;
  }
  async findAggs (qobj, qcwhere) {
    var aggArray = this.buildaggs(qobj);
    if (aggArray.length != 0) {
      qcwhere["attributes"] = {};
      qcwhere["attributes"] = aggArray;
      qcwhere["raw"] = true;
      //提高效率去掉关联和排序,数据记录数量，为聚合
      let tmpwhere = {
        attributes: qcwhere.attributes,
        raw: true,
        where: qcwhere.where
      }
      var aggResult = await this.model.findOne(tmpwhere);
      return aggResult;
    } else {
      return {};
    }

  }
  convertAggResult (aggresult) {
    return aggresult
  }
  async findAndCountAll (qobj, t) {
    var qc = this.buildQuery(qobj);
    let findList = {}
    let count = await this.findCount({ where: qc.where })
    var rows = await this.model.findAll(qc);
    findList["count"] = count
    findList["rows"] = rows
    var aggresult = await this.findAggs(qobj, qc);
    let convertAggResult = this.convertAggResult(aggresult);
    var rtn = {};
    rtn.results = findList;
    rtn.aggresult = convertAggResult;
    return rtn;
  }
  preUpdate (obj) {
    return obj;
  }
  async update (obj, tm) {
    var obj2 = this.preUpdate(obj);
    if (tm != null && tm != 'undefined') {
      await this.model.update(obj2, { where: { id: obj2.id }, transaction: tm });
      let n = await this.model.findOne({ where: { id: obj2.id }, transaction: tm });
      return n
    } else {
      await this.model.update(obj2, { where: { id: obj2.id } });
      let n = await this.model.findById(obj2.id)
      return n
    }
  }
  async bulkCreate (ids, t) {
    if (t != null && t != 'undefined') {
      return await this.model.bulkCreate(ids, { transaction: t });
    } else {
      return await this.model.bulkCreate(ids);
    }
  }

  async updateByWhere (setObj, whereObj, t) {
    let inWhereObj = {}
    if (t && t != 'undefined') {
      if (whereObj && whereObj != 'undefined') {
        inWhereObj["where"] = whereObj;
        inWhereObj["transaction"] = t;
      } else {
        inWhereObj["transaction"] = t;
      }
    } else {
      inWhereObj["where"] = whereObj;
    }
    return this.model.update(setObj, inWhereObj);
  }
  async customExecAddOrPutSql (sql, paras = null) {
    return this.db.query(sql, paras);
  }
  async customQuery (sql, paras, t) {
    var tmpParas = null;//||paras=='undefined'?{type: this.db.QueryTypes.SELECT }:{ replacements: paras, type: this.db.QueryTypes.SELECT };
    if (t && t != 'undefined') {
      if (paras == null || paras == 'undefined') {
        tmpParas = { type: this.db.QueryTypes.SELECT };
        tmpParas.transaction = t;
      } else {
        tmpParas = { replacements: paras, type: this.db.QueryTypes.SELECT };
        tmpParas.transaction = t;
      }
    } else {
      tmpParas = paras == null || paras == 'undefined' ? { type: this.db.QueryTypes.SELECT } : { replacements: paras, type: this.db.QueryTypes.SELECT };
    }
    return this.db.query(sql, tmpParas);
  }
  async findCount (whereObj = null) {
    return this.model.count(whereObj, { logging: false }).then(c => {
      return c;
    });
  }
  async findSum (fieldName, whereObj = null) {
    return this.model.sum(fieldName, whereObj);
  }
  async getPageList (pageIndex, pageSize, whereObj = null, orderObj = null, attributesObj = null, includeObj = null) {
    var tmpWhere = {};
    tmpWhere.limit = pageSize;
    tmpWhere.offset = (pageIndex - 1) * pageSize;
    if (whereObj != null) {
      tmpWhere.where = whereObj;
    }
    if (orderObj != null && orderObj.length > 0) {
      tmpWhere.order = orderObj;
    }
    if (attributesObj != null && attributesObj.length > 0) {
      tmpWhere.attributes = attributesObj;
    }
    if (includeObj != null && includeObj.length > 0) {
      tmpWhere.include = includeObj;
      tmpWhere.distinct = true;
    } else {
      tmpWhere.raw = true;
    }
    return await this.model.findAndCountAll(tmpWhere);
  }
  async findOne (obj, attributes = []) {
    if (attributes.length > 0) {
      return this.model.findOne({ "where": obj, attributes, row: true });
    } else {
      return this.model.findOne({ "where": obj, row: true });
    }
  }
  async findOneWithTm (obj, t) {
    return this.model.findOne({ "where": obj, transaction: t });
  }
  async findById (oid) {
    return this.model.findById(oid);
  }
  async findAll (obj, include = [], other = {}) {
    return this.model.findAll({ "where": obj, include, row: true, ...other });
  }
}
module.exports = Dao;
