
'use strict';

const Service = require('egg').Service;
const R = require('ramda');
const _ = require('lodash');
const moment = require('moment');

class BackService extends Service {
  // 登录
  async login(input) {
    const { ctx } = this;
    const { account, password } = input;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { account, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('用户不存在');
    }

    console.log(ctx.helper.md5(password + 'course'));
    if (userInfo.password !== ctx.helper.md5(password + 'course')) {
      ctx.failed('密码错误');
    }

    const authToken = await this.service.jwt.apply({ user_uuid: userInfo.id });
    await this.app.memcache.set('course_back_auth_token_' + userInfo.id, authToken, 3600);

    const institutionId = ctx.isEmpty(userInfo.institution_id) ? 0 : userInfo.institution_id;
    let institutionName = '';
    if (institutionId > 0) {
      const institution = await ctx.classModel.V5.CourseV5Institution.findOne({ where: { id: institutionId } });
      institutionName = ctx.isEmpty(institution) ? '' : institution.name;
    }

    return { institution_id: institutionId, institution_name: institutionName, auth_token: authToken };
  }

  // 获取菜单
  async getMenuList() {
    const { ctx } = this;
    const userUuid = ctx.userUuid;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('无效用户');
    }

    let menuList = [];
    if (userInfo.is_admin > 0) {
      menuList = await ctx.classModel.CourseBackMenu.findAll({ where: { is_deleted: 0 }, attributes: [ 'id', 'title', 'path', 'icon', 'parent_id', 'sort' ], order: [[ 'sort', 'asc' ]], raw: true });
    } else {
      const userToMenuList = await ctx.classModel.CourseBackUserToMenu.findAll({ where: { user_uuid: userUuid, is_deleted: 0 } });
      menuList = await ctx.classModel.CourseBackMenu.findAll({ where: { id: { $in: R.pluck('menu_id', userToMenuList) }, is_deleted: 0 }, attributes: [ 'id', 'title', 'path', 'icon', 'parent_id', 'sort' ], order: [[ 'sort', 'asc' ]], raw: true });
    }

    for (const i in menuList) {
      menuList[i].subs = [];
    }
    const menu = _.groupBy(menuList, 'id');

    for (const v of menuList) {
      if (v.parent_id > 0 && !ctx.isEmpty(menu[v.parent_id])) {
        menu[v.parent_id][0].subs.push(v);
      }
    }

    const results = [];
    for (const i in menu) {
      if (menu[i][0].parent_id === 0) {
        results.push(menu[i][0]);
      }
    }

    return { list: results };
  }


  // 订单列表
  async getOrderList(input) {
    const { ctx } = this;
    const userUuid = ctx.userUuid;
    const page = Number(input.page) || 1;
    const limit = Number(input.limit) || 10;
    const offset = (page - 1) * limit;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('用户异常');
    }

    const filter = { where: { type: { $or: [ 1, 3 ] }, status: 1, is_deleted: 0 }, limit, offset, attributes: [ 'id', 'order_no', 'class_id', 'pay', 'pay_time', 'redeem', 'address', 'columns' ], order: [[ 'pay_time', 'desc' ]] };
    let filterClassIds = [];
    if (!ctx.isEmpty(input.class_name)) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { name: { $like: `%${input.class_name}%` } }, attributes: [ 'id' ] });
      filterClassIds = R.pluck('id', classList);
      filter.where.class_id = { $in: filterClassIds };
    }

    if (!ctx.isEmpty(input.user_name)) {
      filter.where.address = { $like: `%${input.user_name}%` };
    }

    if (!ctx.isEmpty(input.start_time)) {
      if (!ctx.isEmpty(input.end_time)) {
        filter.where.pay_time = { $gte: input.start_time, $lte: input.end_time };
      } else {
        filter.where.pay_time = { $gte: input.start_time };
      }
    } else if (!ctx.isEmpty(input.end_time)) {
      filter.where.pay_time = { $lte: input.end_time };
    }

    if (userInfo.is_admin === 0) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { institution_id: userInfo.institution_id }, attributes: [ 'id' ] });
      const classIds = ctx.isEmpty(input.class_name) ? R.pluck('id', classList) : _.intersection(filterClassIds, R.pluck('id', classList));
      filter.where.class_id = { $in: classIds };
    }

    const orderList = await ctx.classModel.V5.CourseUserOrder.findAndCountAll(filter);
    if (ctx.isEmpty(orderList.rows)) {
      return {
        list: [],
        page_size: limit,
        total_count: orderList.count,
        page,
      };
    }

    let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { id: { $in: _.uniq(R.pluck('class_id', orderList.rows)) } }, attributes: [ 'id', 'name' ], raw: true });
    classList = _.groupBy(classList, 'id');

    const results = [];
    for (const v of orderList.rows) {
      results.push({
        id: v.id,
        order_no: v.order_no,
        class_id: v.class_id,
        class_name: ctx.isEmpty(classList[v.class_id]) ? '' : classList[v.class_id][0].name,
        pay: v.pay,
        pay_time: v.pay_time,
        redeem_code: v.redeem,
        address: ctx.isEmpty(v.address) ? {} : JSON.parse(v.address),
        columns: ctx.isEmpty(v.columns) ? {} : JSON.parse(v.columns),
      });
    }

    const ret = {
      list: results,
      page_size: limit,
      total_count: orderList.count,
      page,
    };

    return ret;
  }


  // 获取兑换码列表
  async getRedeemCodeList(input) {
    const { ctx } = this;
    const userUuid = ctx.userUuid;
    const page = Number(input.page) || 1;
    const limit = Number(input.limit) || 10;
    const offset = (page - 1) * limit;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('用户异常');
    }

    const filter = { where: { status: 1, is_deleted: 0 }, limit, offset, order: [[ 'id', 'desc' ]] };
    let filterClassIds = [];
    if (!ctx.isEmpty(input.class_name)) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { name: { $like: `%${input.class_name}%` } }, attributes: [ 'id' ] });
      filterClassIds = R.pluck('id', classList);
      filter.where.class_id = { $in: filterClassIds };
    }

    if (!ctx.isEmpty(userInfo.institution_id) && userInfo.institution_id > 0) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { institution_id: userInfo.institution_id }, attributes: [ 'id' ] });
      filterClassIds = ctx.isEmpty(input.class_name) ? R.pluck('id', classList) : _.intersection(filterClassIds, R.pluck('id', classList));
      filter.where.class_id = { $in: filterClassIds };
    }

    const redeemCodeList = await ctx.classModel.V5.CourseRedeemCode.findAndCountAll(filter);
    if (ctx.isEmpty(redeemCodeList.rows)) {
      return {
        list: [],
        page_size: limit,
        total_count: redeemCodeList.count,
        page,
      };
    }

    let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { id: { $in: _.uniq(R.pluck('class_id', redeemCodeList.rows)) } }, attributes: [ 'id', 'name' ], raw: true });
    classList = _.groupBy(classList, 'id');

    const results = [];
    for (const v of redeemCodeList.rows) {
      results.push({
        id: v.id,
        class_id: v.class_id,
        class_name: ctx.isEmpty(classList[v.class_id]) ? '' : classList[v.class_id][0].name,
        code: v.code,
        channel: v.channel,
        is_used: v.is_used,
        used_time: v.used_time,
        created_time: v.created_time,
      });
    }

    const ret = {
      list: results,
      page_size: limit,
      total_count: redeemCodeList.count,
      page,
    };

    return ret;
  }


  // 获取已使用兑换码列表
  async getUsedRedeemCodeList(input) {
    const { ctx } = this;
    const userUuid = ctx.userUuid;
    const page = Number(input.page) || 1;
    const limit = Number(input.limit) || 10;
    const offset = (page - 1) * limit;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('用户异常');
    }

    const filter = { where: { is_used: 1, status: 1, is_deleted: 0 }, limit, offset, order: [[ 'used_time', 'desc' ]] };
    let filterClassIds = [];
    if (!ctx.isEmpty(input.class_name)) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { name: { $like: `%${input.class_name}%` } }, attributes: [ 'id' ] });
      filterClassIds = R.pluck('id', classList);
      filter.where.class_id = { $in: filterClassIds };
    }

    if (!ctx.isEmpty(userInfo.institution_id) && userInfo.institution_id > 0) {
      const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { institution_id: userInfo.institution_id }, attributes: [ 'id' ] });
      filterClassIds = ctx.isEmpty(input.class_name) ? R.pluck('id', classList) : _.intersection(filterClassIds, R.pluck('id', classList));
      filter.where.class_id = { $in: filterClassIds };
    }

    if (!ctx.isEmpty(input.start_time)) {
      if (!ctx.isEmpty(input.end_time)) {
        filter.where.used_time = { $gte: input.start_time, $lte: input.end_time };
      } else {
        filter.where.used_time = { $gte: input.start_time };
      }
    } else if (!ctx.isEmpty(input.end_time)) {
      filter.where.used_time = { $lte: input.end_time };
    }

    const redeemCodeList = await ctx.classModel.V5.CourseRedeemCode.findAndCountAll(filter);
    if (ctx.isEmpty(redeemCodeList.rows)) {
      return {
        list: [],
        page_size: limit,
        total_count: redeemCodeList.count,
        page,
      };
    }

    let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { id: { $in: _.uniq(R.pluck('class_id', redeemCodeList.rows)) } }, attributes: [ 'id', 'name' ], raw: true });
    classList = _.groupBy(classList, 'id');

    let userList = await ctx.classModel.V5.CourseUser.findAll({ where: { uuid: { $in: _.uniq(R.pluck('user_uuid', redeemCodeList.rows)) } }, attributes: [ 'uuid', 'phone' ], raw: true });
    userList = _.groupBy(userList, 'uuid');

    let orderList = await ctx.classModel.V5.CourseUserOrder.findAll({ where: { redeem: { $in: _.uniq(R.pluck('code', redeemCodeList.rows)) }, type: 2, status: 1, is_deleted: 0 }, attributes: [ 'redeem', 'order_no' ], raw: true });
    orderList = _.groupBy(orderList, 'redeem');

    const results = [];
    for (const v of redeemCodeList.rows) {
      results.push({
        id: v.id,
        class_id: v.class_id,
        class_name: ctx.isEmpty(classList[v.class_id]) ? '' : classList[v.class_id][0].name,
        code: v.code,
        channel: v.channel,
        phone: ctx.isEmpty(userList[v.user_uuid]) ? '' : userList[v.user_uuid][0].phone,
        order_no: ctx.isEmpty(orderList[v.code]) ? '' : orderList[v.code][0].order_no,
        used_time: v.used_time,
        created_time: v.created_time,
      });
    }

    const ret = {
      list: results,
      page_size: limit,
      total_count: redeemCodeList.count,
      page,
    };

    return ret;
  }


  // 生成兑换码
  async addRedeemCode(input) {
    const { ctx } = this;
    const num = Number(input.num) || 0;

    const data = [];
    for (let i = 0; i < num; i++) {
      const tmp = {
        code: (ctx.helper.md5(moment().unix()).slice(-2) + await this.getRandomString(8)).toUpperCase(),
        channel: input.channel || '',
        class_id: input.class_id || 0,
      };
      data.push(tmp);
    }
    await ctx.classModel.V5.CourseRedeemCode.bulkCreate(data);

    return { result: true };
  }


  async getRandomString(n) {
    const chars = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
    let ret = '';
    for (let i = 0; i < n; i++) {
      const id = Math.floor(Math.random() * 36);
      ret += chars[id];
    }
    return ret;
  }


  // 获取机构和课程
  async getClassList(input) {
    const { ctx } = this;
    const userUuid = ctx.userUuid;
    const page = Number(input.page) || 1;
    const limit = Number(input.limit) || 10;
    const offset = (page - 1) * limit;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('用户异常');
    }

    const filter = userInfo.is_admin === 0 ? { where: { id: userInfo.institution_id, status: 1, is_deleted: 0 }, attributes: [ 'id', 'name' ], limit, offset, raw: true } : { where: { status: 1, is_deleted: 0 }, limit, offset, attributes: [ 'id', 'name' ] };
    if (!ctx.isEmpty(input.institution_name)) {
      filter.where.name = { $like: `%${input.institution_name}%` };
    }

    const institutionList = await ctx.classModel.V5.CourseV5Institution.findAll(filter);
    if (ctx.isEmpty(institutionList)) {
      return {
        list: [],
      };
    }

    let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { institution_id: { $in: R.pluck('id', institutionList) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'institution_id', 'name' ] });
    classList = _.groupBy(classList, 'institution_id');

    const results = [];
    for (const v of institutionList) {
      results.push({
        id: v.id,
        name: v.name,
        class: ctx.isEmpty(classList[v.id]) ? [] : classList[v.id],
      });
    }

    return {
      list: results,
    };
  }


  // 导出订单
  async exportOrder(input) {
    const { ctx } = this;
    input.page = 1;
    input.limit = 9999;

    let orderList = await this.getOrderList(input);
    orderList = orderList.list;

    if (ctx.isEmpty(orderList)) {
      ctx.failed('无有效数据');
    }

    const results = [];
    for (const v of orderList) {
      const address = ctx.isEmpty(v.address) ? { province: '', city: '', area: '', address: '', name: '', phone: '' } : v.address;
      results.push({
        order_no: v.order_no,
        class_id: v.class_id,
        class_name: v.class_name,
        pay: v.pay,
        pay_time: v.pay_time,
        type: v.type === 1 ? '微信支付' : '兑换码',
        redeem: v.redeem,
        province: address.province,
        city: address.city,
        area: address.area,
        address: address.address,
        name: address.name,
        phone: address.phone,
      });
    }

    await ctx.service.excel
      .newExport()
      .newSheet(results, '订单列表')
      .newColumn('order_no', '订单编号')
      .newColumn('class_name', '课程')
      .newColumn('pay', '支付金额')
      .newColumn('pay_time', '支付时间')
      .newColumn('type', '支付类型')
      .newColumn('redeem', '兑换码')
      .newColumn('province', '省')
      .newColumn('city', '市')
      .newColumn('area', '区')
      .newColumn('address', '详细地址')
      .newColumn('name', '姓名')
      .newColumn('phone', '手机')
      .setFileName('订单列表')
      .get();

    return true;

  }


  // 导出兑换码
  async exportRedeemCode(input) {
    const { ctx } = this;
    input.page = 1;
    input.limit = 9999;

    let orderList = await this.getRedeemCodeList(input);
    orderList = orderList.list;

    if (ctx.isEmpty(orderList)) {
      ctx.failed('无有效数据');
    }

    const results = [];
    for (const v of orderList) {
      results.push({
        class_name: v.class_name,
        code: v.code,
        channel: v.channel,
        is_used: v.is_used === 1 ? '是' : '否',
        used_time: v.used_time,
        created_time: v.created_time,
      });
    }

    await ctx.service.excel
      .newExport()
      .newSheet(results, '兑换码列表')
      .newColumn('class_name', '课程')
      .newColumn('code', '兑换码')
      .newColumn('channel', '渠道')
      .newColumn('is_used', '是否已用')
      .newColumn('used_time', '使用时间')
      .newColumn('created_time', '生成时间')
      .setFileName('兑换码列表')
      .get();

    return true;

  }

  // 导出已使用兑换码
  async exportUsedRedeemCode(input) {
    const { ctx } = this;
    input.page = 1;
    input.limit = 9999;

    let orderList = await this.getUsedRedeemCodeList(input);
    orderList = orderList.list;

    if (ctx.isEmpty(orderList)) {
      ctx.failed('无有效数据');
    }

    const results = [];
    for (const v of orderList) {
      results.push({
        class_name: v.class_name,
        code: v.code,
        channel: v.channel,
        phone: v.phone,
        order_no: v.order_no,
        used_time: v.used_time,
        created_time: v.created_time,
      });
    }

    await ctx.service.excel
      .newExport()
      .newSheet(results, '兑换码列表')
      .newColumn('class_name', '课程')
      .newColumn('code', '兑换码')
      .newColumn('channel', '渠道')
      .newColumn('phone', '手机号')
      .newColumn('order_no', '订单编号')
      .newColumn('used_time', '使用时间')
      .newColumn('created_time', '生成时间')
      .setFileName('兑换码列表')
      .get();

    return true;

  }


  // 获取额外字段
  async getBackColumns() {
    const { ctx } = this;
    const userUuid = ctx.userUuid;

    const userInfo = await ctx.classModel.CourseBackUser.findOne({ where: { id: userUuid, is_deleted: 0 } });
    if (ctx.isEmpty(userInfo)) {
      ctx.failed('无效用户');
    }

    let columns = [];
    if (userInfo.is_admin > 0) {
      columns = await ctx.classModel.CourseBackColumn.findAll({ where: { status: 1 }, attributes: [ 'title', 'column' ] });
    } else {
      columns = await ctx.classModel.V5.CourseV5Institution.findOne({ where: { id: userInfo.institution_id }, attributes: [ 'back_column' ] });
      columns = (ctx.isEmpty(columns) || ctx.isEmpty(columns.back_column)) ? [] : eval(columns.back_column);
      columns = await ctx.classModel.CourseBackColumn.findAll({ where: { column: { $in: columns }, status: 1 }, attributes: [ 'title', 'column' ] });
    }
    const ret = {
      list: columns,
    };

    return ret;
  }
}

module.exports = BackService;
