
'use strict';

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

class ReportService extends Service {
  // 获取问题列表
  async getQuestionList(catId) {
    const { ctx } = this;

    // 获取用户宝宝年龄段
    const userBabyInfo = await ctx.classModel.V5.CourseV5UserBaby.findOne({ where: { user_uuid: ctx.userUuid, status: 1, is_deleted: 0 } });
    if (ctx.isEmpty(userBabyInfo) || ctx.isEmpty(userBabyInfo.age)) {
      ctx.failed('请先选择您的宝宝年龄');
    }

    const questionList = await ctx.classModel.V5.CourseV5Question.findAll({ where: { cat_id: catId, age_id: userBabyInfo.age, status: 1, is_deleted: 0 }, order: [[ 'sort', 'asc' ]] });
    if (ctx.isEmpty(questionList)) {
      return { list: [] };
    }

    // 获取所有选项
    let answerList = await ctx.classModel.V5.CourseV5Answer.findAll({ where: { question_id: { $in: R.pluck('id', questionList) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'question_id', 'title', 'sub_title', 'selected_icon', 'unselected_icon' ], order: [[ 'sort', 'asc' ]] });
    answerList = _.groupBy(answerList, 'question_id');

    const results = [];
    let number = 1;
    for (const v of questionList) {
      results.push({
        id: v.id,
        number: number++,
        cat_id: v.cat_id,
        title: v.title,
        style: v.style,
        type: v.type,
        answer: ctx.isEmpty(answerList[v.id]) ? [] : answerList[v.id],
      });
    }

    const ret = {
      list: results,
    };

    return ret;
  }

  // 生成报告
  async generateReport(input) {
    const { ctx } = this;
    const data = eval(input.data);

    let answerIds = [];
    for (const v of data) {
      answerIds = _.concat(answerIds, v.answers);
    }
    const answerToReportColumnDetailList = await ctx.classModel.V5.CourseV5AnswerToReportColumnDetail.findAll({ where: { answer_id: { $in: answerIds }, status: 1, is_deleted: 0 }, attributes: [ 'report_column_detail_id' ] });
    const reportColumnDetailIds = _.uniq(R.pluck('report_column_detail_id', answerToReportColumnDetailList));

    const result = {
      user_uuid: ctx.userUuid,
      cat_id: input.cat_id,
      report_column_detail_ids: JSON.stringify(reportColumnDetailIds),
      answer: input.data,
    };
    const userReport = await ctx.classModel.V5.CourseUserReport.findOne({ where: { user_uuid: ctx.userUuid, cat_id: input.cat_id, status: 1, is_deleted: 0 } });
    if (ctx.isEmpty(userReport)) {
      await ctx.classModel.V5.CourseUserReport.findOrCreate({ where: { user_uuid: ctx.userUuid, cat_id: input.cat_id, status: 1, is_deleted: 0 }, defaults: result });
    } else {
      await ctx.classModel.V5.CourseUserReport.update(result, { where: { id: userReport.id } });
    }

    const report = await this.getReportByCategory(input.cat_id);
    return report;
  }

  // 获取报告详情
  async getReportByCategory(catId) {
    const { ctx } = this;

    const userReportInfo = await ctx.classModel.V5.CourseUserReport.findOne({ user_uuid: ctx.userUuid, cat_id: catId, status: 1, is_deleted: 0 });
    if (ctx.isEmpty(userReportInfo)) {
      ctx.failed('尚未生成报告');
    }

    const category = await ctx.classModel.V5.CourseV5Category.findOne({ where: { id: userReportInfo.cat_id }, attributes: [ 'name', 'url' ] });

    let reportColumnDetailList = ctx.isEmpty(userReportInfo.report_column_detail_ids) ? [] : await ctx.classModel.V5.CourseV5ReportColumnDetail.findAll({ where: { id: { $in: eval(userReportInfo.report_column_detail_ids) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'report_column_id', 'sub_title', 'level', 'content', 'advice' ], raw: true });
    const reportColumnList = await ctx.classModel.V5.CourseV5ReportColumn.findAll({ where: { id: { $in: R.pluck('report_column_id', reportColumnDetailList) } }, order: [[ 'sort', 'asc' ]], attributes: [ 'id', 'title' ], raw: true });
    reportColumnDetailList = _.groupBy(reportColumnDetailList, 'report_column_id');

    const report = [];
    for (const v of reportColumnList) {
      report.push({
        id: v.id,
        title: v.title,
        sub_title: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].sub_title,
        level: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].level,
        content: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].content,
        advice: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].advice,
      });
    }

    const tags = await this.getReportTags(userReportInfo);
    const recommendClassList = await this.getRecommendClassListByReport(userReportInfo.answer);

    const userBabyInfo = await ctx.classModel.V5.CourseV5UserBaby.findOne({ where: { user_uuid: userReportInfo.user_uuid, status: 1, is_deleted: 0 }, attributes: [ 'user_uuid', 'baby_sex', 'baby_name' ] });

    const ret = {
      category: ctx.isEmpty(category) ? {} : category,
      tags,
      report,
      user: userBabyInfo,
      recommend_class_list: recommendClassList,
    };

    return ret;
  }

  async getReportById(reportId) {
    const { ctx } = this;

    const userReportInfo = await ctx.classModel.V5.CourseUserReport.findOne({ id: reportId, status: 1, is_deleted: 0 });
    if (ctx.isEmpty(userReportInfo)) {
      ctx.failed('尚未生成报告');
    }

    const category = await ctx.classModel.V5.CourseV5Category.findOne({ where: { id: userReportInfo.cat_id }, attributes: [ 'name', 'url' ] });

    let reportColumnDetailList = ctx.isEmpty(userReportInfo.report_column_detail_ids) ? [] : await ctx.classModel.V5.CourseV5ReportColumnDetail.findAll({ where: { id: { $in: eval(userReportInfo.report_column_detail_ids) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'report_column_id', 'sub_title', 'level', 'content', 'advice' ], raw: true });
    const reportColumnList = await ctx.classModel.V5.CourseV5ReportColumn.findAll({ where: { id: { $in: R.pluck('report_column_id', reportColumnDetailList) } }, order: [[ 'sort', 'asc' ]], attributes: [ 'id', 'title' ], raw: true });
    reportColumnDetailList = _.groupBy(reportColumnDetailList, 'report_column_id');

    const report = [];
    for (const v of reportColumnList) {
      report.push({
        id: v.id,
        title: v.title,
        sub_title: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].sub_title,
        level: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].level,
        content: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].content,
        advice: ctx.isEmpty(reportColumnDetailList[v.id]) ? '' : reportColumnDetailList[v.id][0].advice,
      });
    }

    const tags = await this.getReportTags(userReportInfo);
    const recommendClassList = await this.getRecommendClassListByReport(userReportInfo.answer);

    const userBabyInfo = await ctx.classModel.V5.CourseV5UserBaby.findOne({ where: { user_uuid: userReportInfo.user_uuid, status: 1, is_deleted: 0 }, attributes: [ 'user_uuid', 'baby_sex', 'baby_name' ] });

    const ret = {
      category: ctx.isEmpty(category) ? {} : category,
      tags,
      report,
      user: userBabyInfo,
      recommend_class_list: recommendClassList,
    };

    return ret;
  }

  // 获取报告列表
  async getReportList() {
    const { ctx } = this;
    const userUuid = ctx.userUuid;

    const userReportList = await ctx.classModel.V5.CourseUserReport.findAll({ where: { user_uuid: userUuid, status: 1, is_deleted: 0 } });
    const categoryIds = _.uniq(R.pluck('cat_id', userReportList));

    let categoryList = await ctx.classModel.V5.CourseV5Category.findAll({ where: { id: { $in: categoryIds } } });
    categoryList = _.groupBy(categoryList, 'id');

    const results = [];
    const checkIds = [];
    for (const v of userReportList) {
      if (!checkIds.includes(v.cat_id)) {
        const category = ctx.isEmpty(categoryList[v.cat_id]) ? '' : categoryList[v.cat_id][0].name;
        results.push({
          id: v.id,
          title: category,
          icon: ctx.isEmpty(categoryList[v.cat_id]) ? '' : categoryList[v.cat_id][0].report_icon,
          created_time: v.created_time,
        });
        checkIds.push(v.cat_id);
      }
    }

    const ret = {
      list: results,
      total_count: results.length,
    };

    return ret;
  }

  // 获取标签
  async getReportTags(report) {
    const { ctx } = this;
    const userBabyInfo = await ctx.classModel.V5.CourseV5UserBaby.findOne({ where: { user_uuid: report.user_uuid, status: 1, is_deleted: 0 } });

    const tags = [];
    if (userBabyInfo.baby_sex === 1) {
      tags.push('小王子');
    } else {
      tags.push('小公主');
    }
    if (!ctx.isEmpty(userBabyInfo.baby_age)) {
      const age = await ctx.classModel.V5.CourseV5Age.findOne({ where: { id: userBabyInfo.baby_age }, attributes: [ 'name' ] });
      if (!ctx.isEmpty(age)) {
        tags.push(age.name);
      }
    }
    if (!ctx.isEmpty(userBabyInfo.baby_birth)) {
      let diffYear = moment().diff(userBabyInfo.baby_birth, 'years');
      diffYear = diffYear > 0 ? diffYear : 1;
      tags.push(`${diffYear}岁`);
    }

    // 问题对应的tag
    const data = eval(report.answer);
    let answerIds = [];
    for (const v of data) {
      answerIds = _.concat(answerIds, v.answers);
    }
    const tagList = await ctx.classModel.V5.CourseV5Answer.findAll({ where: { id: { $in: answerIds } }, attributes: [ 'tag' ] });
    console.log(tagList);
    for (const v of tagList) {
      if (!ctx.isEmpty(v.tag)) {
        tags.push(v.tag);
      }
    }

    return tags;
  }

  // 获取推荐课程
  async getRecommendClassListByReport(data) {
    const { ctx } = this;
    // const data = eval(input.data);
    data = eval(data);

    // 取出所有回答
    let answerIds = [];
    for (const v of data) {
      answerIds = _.union(answerIds, v.answers);
    }

    // 获取所有回答筛选相关信息
    const answerFilterList = await ctx.classModel.V5.CourseV5AnswerToFilter.findAll({ where: { answer_id: { $in: answerIds }, status: 1, is_deleted: 0 }, raw: true });

    // 先做筛选
    const where = await this.classFilter(answerFilterList);
    let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where, attributes: [ 'id', 'institution_id', 'name', 'logo', 'age', 'price', 'price_type', 'mode', 'time', 'class_amount', 'multi_classes', 'cycle', 'sort' ], raw: true });
    // 格式化课程
    classList = await this.formatClassList(classList);

    // 然后进行打分
    classList = await this.calcClassScore(classList, answerFilterList);

    // 按照分数降序，价格升序的顺序排列
    classList = _.orderBy(classList, [ 'score', 'filter_price' ], [ 'desc', 'asc' ]);
    classList = classList.slice(0, 3);

    for (let i = 0; i < classList.length; i++) {
      classList[i].match = 99 - i * 3 - Math.floor(Math.random() * 3);
    }

    return classList;
  }


  // 筛选课程
  async classFilter(answerFilterList) {
    const { ctx } = this;

    const where = { status: 1, is_deleted: 0 };
    let classIds = [];
    let classFlag = false;
    let tmpFilter = {};
    let tmpClassList = [];
    for (const v of answerFilterList) {
      if (v.type === 1) {
        // 判断是否是课程的额外字段
        if (v.column_type === 1) { // 课程字段
          switch (v.column) {
            case 'price_filter':
              where.price_filter = await this.getOptionValue(v);
              break;
            case 'price_type':
              where.price_type = await this.getOptionValue(v);
              break;
            case 'mode':
              where.mode = await this.getOptionValue(v);
              break;
            case 'time':
              where.time = await this.getOptionValue(v);
              break;
            case 'class_amount':
              where.class_amount = await this.getOptionValue(v);
              break;
            case 'multi_classes':
              where.multi_classes = await this.getOptionValue(v);
              break;
            case 'cycle':
              where.cycle = await this.getOptionValue(v);
              break;
            case 'type':
              tmpFilter = { where: { type_id: await this.getOptionValue(v), status: 1, is_deleted: 0 }, attributes: [ 'class_id' ] };
              tmpClassList = await ctx.classModel.V5.CourseV5ClassToType.findAll(tmpFilter);
              classIds = classFlag ? _.union(classIds, R.pluck('class_id', tmpClassList)) : R.pluck('class_id', tmpClassList);
              classFlag = true;
              break;
            case 'frequency':
              tmpFilter = { where: { frequency_id: await this.getOptionValue(v), status: 1, is_deleted: 0 }, attributes: [ 'class_id' ] };
              tmpClassList = await ctx.classModel.V5.CourseV5ClassToFrequency.findAll(tmpFilter);
              classIds = classFlag ? _.union(classIds, R.pluck('class_id', tmpClassList)) : R.pluck('class_id', tmpClassList);
              classFlag = true;
              break;
            default:
              break;
          }
        } else if (v.column_type === 2) { // 额外字段
          tmpFilter = { where: { column_id: v.column, value: await this.getOptionValue(v) }, attributes: [ 'class_id' ] };
          tmpClassList = await ctx.classModel.V5.CourseV5ClassToColumn.findAll(tmpFilter);
          classIds = classFlag ? _.union(classIds, R.pluck('class_id', tmpClassList)) : R.pluck('class_id', tmpClassList);
          classFlag = true;
        }
      }
    }
    if (classFlag) {
      where.id = { $in: classIds };
    }

    return where;
  }

  // 获取筛选项操作符和值处理后的数据
  async getOptionValue(filter) {
    let ret = {};
    // 1：=；2：>；3：>=；4：<；5：<=；6：in；7：!=
    switch (filter.column_option) {
      case 1:
        ret = filter.column_value;
        break;
      case 2:
        ret = { $gt: filter.column_value };
        break;
      case 3:
        ret = { $gte: filter.column_value };
        break;
      case 4:
        ret = { $lt: filter.column_value };
        break;
      case 5:
        ret = { $lte: filter.column_value };
        break;
      case 6:
        ret = { $in: eval(filter.value) };
        break;
      case 7:
        ret = { $not: filter.column_value };
        break;
      default:
        break;
    }

    return ret;
  }

  // 格式化课程列表
  async formatClassList(classList) {
    const { ctx } = this;

    const classIds = R.pluck('id', classList);

    // 获取所有年龄段
    let classToAge = await ctx.classModel.V5.CourseV5ClassToAge.findAll({ where: { class_id: { $in: classIds }, status: 1, is_deleted: 0 }, attributes: [ 'class_id', 'age_id' ] });
    let ageList = await ctx.classModel.V5.CourseV5Age.findAll({ where: { id: { $in: R.pluck('age_id', classToAge) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'name' ] });
    classToAge = _.groupBy(classToAge, 'class_id');
    ageList = _.groupBy(ageList, 'id');

    // 获取所有课程类型
    let classToType = await ctx.classModel.V5.CourseV5ClassToType.findAll({ where: { class_id: { $in: classIds }, status: 1, is_deleted: 0 }, attributes: [ 'class_id', 'type_id' ] });
    let typeList = await ctx.classModel.V5.CourseV5Type.findAll({ where: { id: { $in: R.pluck('type_id', classToType) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'name' ] });
    classToType = _.groupBy(classToType, 'class_id');
    typeList = _.groupBy(typeList, 'id');

    // 获取所有授课频次
    let classToFrequency = await ctx.classModel.V5.CourseV5ClassToFrequency.findAll({ where: { class_id: { $in: classIds }, status: 1, is_deleted: 0 }, attributes: [ 'class_id', 'frequency_id' ] });
    let frequencyList = await ctx.classModel.V5.CourseV5Frequency.findAll({ where: { id: { $in: R.pluck('frequency_id', classToFrequency) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'name' ] });
    classToFrequency = _.groupBy(classToFrequency, 'class_id');
    frequencyList = _.groupBy(frequencyList, 'id');

    // 获取所有额外字段
    let classToColumn = await ctx.classModel.V5.CourseV5ClassToColumn.findAll({ where: { class_id: { $in: classIds }, status: 1, is_deleted: 0 }, attributes: [ 'class_id', 'column_id', 'value' ] });
    let columnList = await ctx.classModel.V5.CourseV5Column.findAll({ where: { id: { $in: R.pluck('column_id', classToColumn) }, status: 1, is_deleted: 0 }, attributes: [ 'id', 'name' ] });
    classToColumn = _.groupBy(classToColumn, 'class_id');
    columnList = _.groupBy(columnList, 'id');

    // 获取所有机构
    let institutionList = await ctx.classModel.V5.CourseV5Institution.findAll({ where: { id: { $in: R.pluck('institution_id', classList) } } });
    institutionList = _.groupBy(institutionList, 'id');

    const ret = [];
    for (const v of classList) {
      const classAgeList = [];
      if (!ctx.isEmpty(classToAge[v.id])) {
        for (const j of classToAge[v.id]) {
          if (!ctx.isEmpty(ageList[j.age_id])) {
            classAgeList.push({
              id: j.age_id,
              name: ageList[j.age_id][0].name,
            });
          }
        }
      }

      const classTypeList = [];
      if (!ctx.isEmpty(classToType[v.id])) {
        for (const j of classToType[v.id]) {
          if (!ctx.isEmpty(typeList[j.type_id])) {
            classTypeList.push({
              id: j.type_id,
              name: typeList[j.type_id][0].name,
            });
          }
        }
      }

      const classFrequencyList = [];
      if (!ctx.isEmpty(classToFrequency[v.id])) {
        for (const j of classToFrequency[v.id]) {
          if (!ctx.isEmpty(frequencyList[j.frequency_id])) {
            classFrequencyList.push({
              id: j.frequency_id,
              name: frequencyList[j.frequency_id][0].name,
            });
          }
        }
      }

      const classColumnList = [];
      if (!ctx.isEmpty(classToColumn[v.id])) {
        for (const j of classToColumn[v.id]) {
          if (!ctx.isEmpty(columnList[j.column_id])) {
            classColumnList.push({
              id: j.column_id,
              name: columnList[j.column_id][0].name,
              value: j.value,
              filter_key: `${j.column_id}---${j.value}`,
            });
          }
        }
      }

      const tmpClass = v;
      tmpClass.institution_name = ctx.isEmpty(institutionList[v.institution_id]) ? '' : institutionList[v.institution_id][0].name;
      tmpClass.age_list = classAgeList;
      tmpClass.type_list = classTypeList;
      tmpClass.frequency_list = classFrequencyList;
      tmpClass.column_list = classColumnList;
      tmpClass.score = 0;

      ret.push(tmpClass);
    }

    return ret;
  }

  // 计算所有公司评分
  async calcClassScore(classList, answerFilterList) {
    const { ctx } = this;
    // 先获取所有评分筛选
    let scoreFilterList = [];
    for (const v of answerFilterList) {
      if (v.type === 2) {
        scoreFilterList.push({
          column_type: v.column_value,
          column: v.column,
          column_value: v.column_value,
          column_filter_key: `${v.column}---${v.column_value}`,
          column_score: v.column_score,
        });
      }
    }
    scoreFilterList = _.groupBy(scoreFilterList, 'column_filter_key');

    const ret = [];
    for (const v of classList) {
      const tmpClass = v;
      // 先计算所有的额外字段
      for (const j of v.column_list) {
        if (!ctx.isEmpty(scoreFilterList[j.filter_key])) {
          tmpClass.score += scoreFilterList[j.filter_key][0].column_score;
        }
      }

      // 计算课程字段
      // 年龄段
      for (const j of v.age_list) {
        if (!ctx.isEmpty(scoreFilterList[`age---${j.id}`])) {
          tmpClass.score += scoreFilterList[`age---${j.id}`][0].column_score;
        }
      }
      // 课程班型
      for (const j of v.type_list) {
        if (!ctx.isEmpty(scoreFilterList[`type---${j.id}`])) {
          tmpClass.score += scoreFilterList[`type---${j.id}`][0].column_score;
        }
      }
      // 授课频次
      for (const j of v.frequency_list) {
        if (!ctx.isEmpty(scoreFilterList[`frequency---${j.id}`])) {
          tmpClass.score += scoreFilterList[`frequency---${j.id}`][0].column_score;
        }
      }
      // 课程类型
      if (!ctx.isEmpty(scoreFilterList[`price_type---${v.price_type}`])) {
        tmpClass.score += scoreFilterList[`price_type---${v.price_type}`][0].column_score;
      }
      // 课程状态
      if (!ctx.isEmpty(scoreFilterList[`mode---${v.mode}`])) {
        tmpClass.score += scoreFilterList[`mode---${v.mode}`][0].column_score;
      }

      ret.push(tmpClass);
    }

    return ret;
  }


  // 获取所有报告推荐课程
  async getAllReportRecommendClassList() {
    const { ctx } = this;

    const userReportList = await ctx.classModel.V5.CourseUserReport.findAll({ where: { user_uuid: ctx.userUuid, status: 1, is_deleted: 0 }, raw: true });
    const categoryIds = _.uniq(R.pluck('cat_id', userReportList));

    let categoryList = await ctx.classModel.V5.CourseV5Category.findAll({ where: { id: { $in: categoryIds } }, attributes: [ 'id', 'name', 'url' ] });
    categoryList = _.groupBy(categoryList, 'id');

    const results = [];
    const checkIds = [];
    for (const v of userReportList) {
      if (!checkIds.includes(v.cat_id)) {
        results.push({
          id: v.id,
          category: ctx.isEmpty(categoryList[v.cat_id]) ? {} : categoryList[v.cat_id][0],
          answer: v.answer,
        });
        checkIds.push(v.cat_id);
      }
    }

    const handle = [];
    for (const i in results) {
      handle.push(this.getRecommendClassListByReport(results[i].answer));
    }
    const handleResult = await Promise.all(handle).then(result => {
      return result;
    }).catch(error => {
      ctx.failed(error);
    });

    const ret = [];
    for (const i in results) {
      ret.push({
        id: results[i].id,
        category: results[i].category,
        recommend_class_list: handleResult[i],
      });
    }

    return { list: ret };
  }
}

module.exports = ReportService;
