const system = require("../system");
class Dao {
  constructor(modelName) {
    this.modelName = modelName;
    this.redisClient = system.getObject("util.redisClient");
    var db = system.getObject("db.common.connection").getCon();
    this.db = db;
    console.log("........set dao model..........");
    this.model = db.models[this.modelName];
  }

  async preCreate(u) {
    if (!u.id && !u.autoIncrement) {
      u.id = await this.redisClient.genrateId(this.modelName);
    }
    return u;
  }
  async create(u, t) {
    var u2 = await this.preCreate(u);
    if (t) {
      return this.model.create(u2, {
        transaction: t
      }).then(u => {
        return u;
      });
    } else {
      return this.model.create(u2, {
        transaction: t
      }).then(u => {
        return u;
      });
    }
  }

  async bulkCreate(objs, t) {
    if (!objs || objs.length == 0) {
      return;
    }
    for (var obj of objs) {
      if (!obj.id && !obj.autoIncrement) {
        obj.id = await this.redisClient.genrateId(this.modelName);
      }
    }
    if (t) {
      return await this.model.bulkCreate(objs, { transaction: t });
    } else {
      return await this.model.bulkCreate(objs);
    }
  }

  static getModelName(ClassObj) {
    return ClassObj["name"].substring(0, ClassObj["name"].lastIndexOf("Dao")).toLowerCase()
  }
  async refQuery(qobj) {
    var w = {};
    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({
        attributes: qobj.fields
      });
    }
  }
  async bulkDelete(ids) {
    var en = await this.model.destroy({
      where: {
        id: {
          [this.db.Op.in]: ids
        }
      }
    });
    return en;
  }
  async delete(qobj) {
    var en = await this.model.findOne({
      where: qobj
    });
    if (en != null) {
      return en.destroy();
    }
    return null;
  }
  extraModelFilter() {
    //return {"key":"include","value":{model:this.db.models.app}};
    return null;
  }
  extraWhere(obj, where) {
    return where;
  }
  orderBy() {
    //return {"key":"include","value":{model:this.db.models.app}};
    return [
      ["created_at", "DESC"]
    ];
  }
  buildQuery(qobj) {
    var linkAttrs = [];
    const pageNo = qobj.pageInfo.pageNo;
    const pageSize = qobj.pageInfo.pageSize;
    const search = qobj.search;
    const orderInfo = qobj.orderInfo; //格式:[["created_at", 'desc']]
    var qc = {};
    //设置分页查询条件
    qc.limit = pageSize;
    qc.offset = (pageNo - 1) * pageSize;
    //默认的查询排序
    if (orderInfo) {
      qc.order = orderInfo;
    } else {
      qc.order = this.orderBy();
    }
    //构造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();
    if (extraFilter) {
      qc[extraFilter.key] = extraFilter.value;
    }
    console.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm");
    console.log(qc);
    return qc;
  }
  async findAndCountAll(qobj, t) {
    var qc = this.buildQuery(qobj);
    var apps = await this.model.findAndCountAll(qc);
    return apps;
  }
  preUpdate(obj) {
    return obj;
  }
  async update(obj, tm) {
    var obj2 = this.preUpdate(obj);
    if (tm != null && tm != 'undefined') {
      return this.model.update(obj2, {
        where: {
          id: obj2.id
        },
        transaction: tm
      });
    } else {
      return this.model.update(obj2, {
        where: {
          id: obj2.id
        }
      });
    }
  }
  async updateByWhere(setObj, whereObj, t) {
    if (t && t != 'undefined') {
      if (whereObj && whereObj != 'undefined') {
        whereObj.transaction = t;
      } else {
        whereObj = {
          transaction: t
        };
      }
    }
    return this.model.update(setObj, whereObj);
  }
  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 customUpdate(sql, paras, t) {
    var tmpParas = null;
    if (t && t != 'undefined') {
      if (paras == null || paras == 'undefined') {
        tmpParas = {
          type: this.db.QueryTypes.UPDATE
        };
        tmpParas.transaction = t;
      } else {
        tmpParas = {
          replacements: paras,
          type: this.db.QueryTypes.UPDATE
        };
        tmpParas.transaction = t;
      }
    } else {
      tmpParas = paras == null || paras == 'undefined' ? {
        type: this.db.QueryTypes.UPDATE
      } : {
        replacements: paras,
        type: this.db.QueryTypes.UPDATE
      };
    }
    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;
    }
    tmpWhere.raw = true;
    return await this.model.findAndCountAll(tmpWhere);
  }
  async findOne(obj, t) {
    var params = {
      "where": obj
    };
    if (t) {
      params.transaction = t;
    }
    return this.model.findOne(params);
  }
  async findById(oid) {
    return this.model.findById(oid);
  }

  async setListCodeName(list, field) {
    if (!list) {
      return;
    }
    for (item of list) {
      await this.setRowCodeName(item, field);
    }
  }
  async setRowCodeName(item, field) {
    if (!item || !field) {
      return;
    }
    var map = this[field + "Map"] || {};
    if (!item) {
      return;
    }
    item[field + "Name"] = map[item[field] || ""] || "";
  }

  async getById(id, attrs) {
    if (!id) {
      return null;
    }

    attrs = attrs || "*";
    var sql = "SELECT " + attrs + " FROM " + this.model.tableName + " where id = :id ";
    var list = await this.customQuery(sql, {
      id: id
    });
    return list && list.length > 0 ? list[0] : null;
  }

  async getListByIds(ids, attrs) {
    if (!ids || ids.length == 0) {
      return [];
    }

    attrs = attrs || "*";
    var sql = "SELECT " + attrs + " FROM " + this.model.tableName + " where id IN (:ids) ";
    return await this.customQuery(sql, {
      ids: ids
    }) || [];
  }

}
module.exports = Dao;