
'use strict';

const Service = require('egg').Service;
const R = require('ramda');
const _ = require('lodash');
const moment = require('moment');
class InstitutionService extends Service {


  // 机构列表页
  async getInstitutions(input) {

    const { ctx } = this;
    const user_uuid = ctx.userUuid;
    const { cats, ages, lat, lng, address, page } = input;
    const distance = !ctx.isEmpty(input.distance) ? Number(input.distance) : 0;
    const where_institutions = input.institutions;
    // 保存定位记录
    if (address && lat && lng) {
      ctx.classModel.V1.CourseLogUserGps.add({ user_uuid, address, lat, lng });
    }

    // 处理条件过滤条件
    const where = { status: 1, is_deleted: 0 };
    if (Number(cats)) {
      const cat_ret = await ctx.classModel.V1.CourseCat.one({ where: { id: cats } });
      const cat_id = cat_ret.id;
      const cat_level = cat_ret.level;
      const next_level = cat_level + 1;
      const next_next_level = cat_level + 2;
      const next_cat = await ctx.classModel.V1.CourseCat.all({ where: { level: next_level, parent_id: cat_id } });
      const next_next_cat = await ctx.classModel.V1.CourseCat.all({ where: { level: next_next_level, first_id: cat_id } });
      let cat_ids = [ cat_id ];
      cat_ids = cat_ids.concat(R.pluck('id', next_cat)).concat(R.pluck('id', next_next_cat));
      const institutions = await ctx.classModel.V1.CourseInstitutionToCat.all({ where: { cat_id: { $in: cat_ids } } });
      const institutions_ids = Array.from(new Set(R.pluck('institution_id', institutions)));
      institutions_ids.length !== 0 ? where.id = { $in: institutions_ids } : [];
    }
    if (Number(ages)) {
      where.max_age = { $gte: ages };
      where.min_age = { $lte: ages };
    }
    if (where_institutions) {
      where.corner = { $ne: '' };
    }

    // 关联校区表查找信息
    const include = [{ model: ctx.classModel.V1.CourseArea, where: { status: 1, is_deleted: 0 }, attributes: [ 'id', 'institution_id', 'name', 'address', 'lat', 'lng' ] }];
    const attributes = [ 'id', 'name', 'type', 'establishment_time', 'class_type', 'teacher_count', 'teacher_experience', 'corner', 'min_age', 'max_age', 'price', 'characteristic' ];
    const institutions = await ctx.classModel.V1.CourseInstitution.findAll({ attributes, include, where });

    const institution_area_list = await this.getInstitutionAreaList(institutions);// 将校区表处理成数组

    // const from = { lat, lng };
    // const area_lbs = await this.computeDistance(institution_area_list, { lat, lng });// 计算距离信息
    const area_distance_list = await this.calcDistance(institution_area_list, { lat, lng }, page, distance);
    const area_distance = area_distance_list.rows;
    const institution_areas = await this.computeDistance(area_distance, { lat, lng });
    for (const i in institution_areas) {
      area_distance[i].distance = Number(institution_areas[i].distance) === 0 ? 999999999.0 : parseFloat(institution_areas[i].distance);
      area_distance[i].duration = institution_areas[i].duration;
      area_distance[i].travel_method = institution_areas[i].travel_method;
      area_distance[i].travel_tips = `距我${area_distance[i].distance}km,开车${area_distance[i].duration}分钟`;
      if (area_distance[i].travel_method === 'walking') {
        area_distance[i].travel_tips = `距我${area_distance[i].distance}km,步行${area_distance[i].duration}分钟`;
      }
      if (Number(institution_areas[i].distance) === 0 && institution_areas[i].duration === 0) {
        area_distance[i].travel_tips = '暂无法计算出距离';
      }
    }
    // const institution_areas = await this.findShortestDistanceAreas(institution_area_list, area_lbs);// 查找最短距离并输出
    // const ret = await this.formatInstitutions(institution_areas);
    const ret = await this.formatInstitutions(area_distance, distance);

    return { count: area_distance_list.count, rows: ret };
  }

  /**
     * 机构详情页
     */
  async getInstitution(input) {

    const { ctx } = this;
    const user_uuid = ctx.userUuid;
    const { institution_id, area_id } = input;
    const lat = ctx.isEmpty(input.lat) ? 0 : input.lat;
    const lng = ctx.isEmpty(input.lng) ? 0 : input.lng;
    const institution = await ctx.classModel.V1.CourseInstitution.one({ where: { id: institution_id } });
    const teachers = await this.getTeachers({ institution_id, limit: 6 });
    const classes = await this.getClasses({ institution_id, limit: 4 });

    const institution_images = await ctx.classModel.V1.CourseImages.all({ where: { type: 1, type_id: institution_id } });// 图片

    // 处理详情页信息
    const current_area = await ctx.classModel.V1.CourseArea.one({ where: { id: area_id } });
    let institution_detail = await this.formatInstitutions([ institution ]);
    institution_detail = institution_detail[0];
    institution_detail.address = current_area.address;
    institution_detail.phone = current_area.phone;
    institution_detail.description = institution.description;
    institution_detail.point = institution.point;
    institution_detail.honor = institution.honor;
    institution_detail.is_collect = 0;

    // 计算校区距离
    const areas_ret = await this.getInstitutionAreas({ institution_id, limit: 1000 });// 校区
    const area_rows = areas_ret.rows;
    const area_lbs = (lat > 0 || lng > 0) ? await this.computeDistance(area_rows, { lat, lng }) : [];// 计算距离信息
    let areas = [];

    for (const i in area_rows) {

      const area = area_rows[i];
      const lbs = i < area_lbs.length ? area_lbs[i] : { distance: 0, duration: 0, travel_method: '' };
      const area_name = area.name;
      const distance = lbs.distance;
      const duration = lbs.duration;

      let travel_tips = `距我${distance}km,开车${duration}分钟`;
      if (lbs.travel_method === 'walking') {
        travel_tips = `距我${distance}km,步行${duration}分钟`;
      }
      if (Number(distance) === 0 && duration === 0) {
        travel_tips = '暂无法计算出距离';
      }
      if (area.id == area_id && area.institution_id == institution_id) {
        institution_detail.travel_tips = travel_tips;
        institution_detail.lat = area.lat;
        institution_detail.lng = area.lng;
      }
      areas.push({
        id: area.id,
        institution_id: area.institution_id,
        name: area_name,
        address: area.address,
        phone: area.phone,
        travel_tips,
        lat: area.lat,
        lng: area.lng,
        distance: Number(distance) === 0 ? 999999999.0 : parseFloat(distance),
      });
    }
    areas = _.orderBy(areas, [ 'distance' ], [ 'asc' ]);

    // 是否收藏过
    const collection_ret = await ctx.classModel.V1.CourseUserCollection.one({ where: { user_uuid, institution_id, is_deleted: 0 } });
    if (collection_ret && collection_ret.id) {
      institution_detail.is_collect = 1;
    }


    // 处理图片
    const photo_album = [];
    const photo_check = []; // 去重
    for (const i in institution_images) {
      const institution_image = institution_images[i];
      if (institution_image.is_video > 0) {
        if (photo_check.includes(institution_image.video_url)) {
          continue;
        } else {
          photo_check.push(institution_image.video_url);
        }
      } else {
        if (photo_check.includes(institution_image.image_url)) {
          continue;
        } else {
          photo_check.push(institution_image.image_url);
        }
      }
      photo_album.push({
        image: institution_image.image_url,
        is_video: institution_image.is_video,
        video_url: institution_image.video_url,
      });
    }
    institution_detail.photo_album = photo_album;

    return { institution_detail, teachers: teachers.rows, classes: classes.rows, areas };
  }

  async getTeacher(teacher_id) {

    const { ctx } = this;
    const where = { id: teacher_id };
    const teacher = await ctx.classModel.V1.CourseTeacher.one({ where });
    teacher.dataValues.point_tags = teacher.point ? teacher.point.split(',') : [];
    teacher.dataValues.work_experience_tags = teacher.work_experience ? teacher.work_experience.split(';') : [];

    const institution = await ctx.classModel.V1.CourseInstitution.find({ where: { id: teacher.institution_id } });
    teacher.dataValues.institution_name = institution.name;

    return teacher;
  }

  async getClass(class_id) {

    const { ctx } = this;
    const where = { id: class_id };
    const classs = await ctx.classModel.V1.CourseClass.one({ where });
    classs.dataValues.age_text = Number(classs.max_age) > 0 ? `${classs.min_age}-${classs.max_age}岁` : '';
    classs.dataValues.point_tags = classs.point ? classs.point.split(',') : [];
    const class_images = await ctx.classModel.V1.CourseImages.findAll({ where: { type: 2, type_id: classs.id } });
    // 处理图片
    const photo_album = [];
    const photo_check = []; // 去重
    for (const i in class_images) {
      const class_image = class_images[i];
      if (class_image.is_video > 0) {
        if (photo_check.includes(class_image.video_url)) {
          continue;
        } else {
          photo_check.push(class_image.video_url);
        }
      } else {
        if (photo_check.includes(class_image.image_url)) {
          continue;
        } else {
          photo_check.push(class_image.image_url);
        }
      }
      photo_album.push({
        image: class_image.image_url,
        is_video: class_image.is_video,
        video_url: class_image.video_url,
      });
    }
    classs.dataValues.photo_album = photo_album;
    classs.dataValues.class_period = classs.class_period > 0 ? classs.class_period : '';

    return classs;
  }

  async getTeachers(input) {

    const { ctx } = this;
    const attributes = [ 'id', 'institution_id', 'name', 'avatar', 'teacher_experience', 'lesson', 'educational_background', 'certificate' ];
    const { institution_id, page, limit } = input;
    const where = { institution_id };
    const teachers = await ctx.classModel.V1.CourseTeacher.list({ attributes, page, limit, where });

    const ret = [];
    for (const i in teachers.rows) {
      const teacher = teachers.rows[i];
      ret.push({
        id: teacher.id,
        institution_id: teacher.institution_id,
        name: teacher.name ? teacher.name : '',
        avatar: teacher.avatar ? teacher.avatar : '',
        teacher_experience: teacher.teacher_experience ? teacher.teacher_experience : '',
        lesson: teacher.lesson ? teacher.lesson : '',
        educational_background: teacher.educational_background ? teacher.educational_background : '',
        certificate: teacher.certificate ? teacher.certificate : '',
      });
    }

    return { page, count: ret.length, rows: ret };

  }

  async getClasses(input) {

    const { ctx } = this;
    const attributes = [ 'id', 'institution_id', 'name', 'type', 'price' ];
    const { institution_id, page, limit } = input;
    const where = { institution_id };
    const classes = await ctx.classModel.V1.CourseClass.list({ attributes, page, limit, where });
    const p_class_images = [];

    // 获取图片信息
    for (const j in classes.rows) {
      const classs = classes.rows[j];
      p_class_images[j] = ctx.classModel.V1.CourseImages.one({ where: { type: 2, type_id: classs.id, is_video: 0 } });
    }
    const class_images = await Promise.all(p_class_images).then(result => { // 等待所有异步内容获取完成
      return result;
    }).catch(error => {
      ctx.failed(error);
    });

    // 格式化课程信息
    const ret = [];
    for (const i in classes.rows) {
      const classs = classes.rows[i];
      classs.dataValues.image = class_images[i] ? class_images[i].image_url : '';
      classs.dataValues.price_text = classs.price ? classs.price : '现场咨询';
      classs.dataValues.class_period = classs.class_period > 0 ? classs.class_period : '';
      ret.push(classs);
    }

    return { page: classes.page, count: classes.count, rows: ret };

  }

  async getInstitutionAreas(input) {

    const { ctx } = this;
    const attributes = [ 'id', 'institution_id', 'name', 'address', 'phone', 'lat', 'lng' ];
    const { institution_id, page, limit } = input;
    const where = { institution_id };
    const areas = await ctx.classModel.V1.CourseArea.list({ attributes, page, limit, where });

    return areas;

  }

  // 机构列表 并有多校区 {id：1，..., course_areas:[{},{}]
  async getInstitutionAreaList(institutions) {
    const { ctx } = this;

    if (!Array.isArray(institutions) || institutions.length === 0) {
      return [];
    }

    const ret = [];
    for (const i in institutions) {
      const institution = institutions[i];
      if (!institution.course_area_v1s || institution.course_area_v1s.length === 0) continue;
      const course_areas = institution.course_area_v1s;
      for (const j in course_areas) {
        const course_area = course_areas[j];
        ret.push({
          id: institution.id,
          name: institution.name,
          type: institution.type,
          image: institution.image,
          establishment_time: institution.establishment_time,
          class_type: institution.class_type,
          teacher_count: institution.teacher_count,
          teacher_experience: institution.teacher_experience,
          corner: institution.corner,
          min_age: institution.min_age,
          max_age: institution.max_age,
          price: institution.price,
          characteristic: institution.characteristic,
          area_id: course_area.id,
          area_name: course_area.name,
          area_address: course_area.address,
          lat: course_area.lat,
          lng: course_area.lng,
        });
      }
    }

    return ret;
  }

  /**
     * 起点（）到多个终点（[{ lng: 120.212997, lat: 30.29133 }];）  计算距离 distance=3km
     * @param {*} lbs_array [{ lng: 120.212997, lat: 30.29133 }]
     * @param {*} from_gps { lng: 120.069206, lat: 30.291121 }
     * @param {*} distance 3
     */
  async computeDistance(lbs_array, from_gps, distance = 3) {

    const { ctx } = this;

    if (!Array.isArray(lbs_array) || lbs_array.length === 0) {
      return [];
    }

    const from = from_gps;
    const lat = from.lat;
    const lng = from.lng;
    // console.info({ lat, lng });
    // 计算距离
    const driving_results = await ctx.service.course.lbs.getLBSDistance('driving', { lat, lng }, lbs_array);
    const walking_results = await ctx.service.course.lbs.getLBSDistance('walking', { lat, lng }, lbs_array);
    if (!walking_results.results && !driving_results.results) {
      return [];
    }

    // 处理距离结果
    const drivings = driving_results.results.map(item => {
      const distance = (item.distance / 1000).toFixed(1);
      const duration = Math.ceil(item.duration / 60);
      return { distance, duration };
    });
    const walkings = walking_results.results.map(item => {
      const distance = (item.distance / 1000).toFixed(2);
      const duration = Math.ceil(item.distance / 80);
      return { distance, duration };
    });

    // 格式化 判断步行或驾车
    const results = [];
    for (const i in lbs_array) {
      const lbs = lbs_array[i];
      const driving = (drivings[i] && drivings[i].distance !== -1) ? drivings[i] : { distance: 0, duration: 0 };
      const walking = (walkings[i] && walkings[i].distance !== -1) ? walkings[i] : { distance: 0, duration: 0 };
      const lbs_distance = driving.distance > distance ? driving : walking;
      const travel_method = driving.distance > distance ? 'driving' : 'walking';
      results.push({
        lat: lbs.lat,
        lng: lbs.lng,
        distance: lbs_distance.distance,
        duration: lbs_distance.duration,
        travel_method,
      });
    }

    return results;

  }

  // 先本地用公式计算距离，然后分页，取对应的再去调腾讯接口
  async calcDistance(lbs_array, from_gps, page = 1, distance = 0) {
    const { ctx } = this;

    if (!Array.isArray(lbs_array) || lbs_array.length === 0) {
      return { count: 0, rows: [] };
    }

    const calcHandle = [];
    for (const v of lbs_array) {
      calcHandle.push(ctx.service.course.lbs.getDistance(v, from_gps));
    }
    const result = await Promise.all(calcHandle).then(result => {
      return result;
    }).catch(error => {
      ctx.failed(error);
    });

    let ret = [];
    for (const i in result) {
      const tmp = lbs_array[i];
      tmp.distance = result[i];
      if (distance === 0 || (distance > 0 && tmp.distance <= distance)) {
        ret.push(tmp);
      }
    }

    const sort = function(a, b) {
      return a.distance - b.distance;
    };

    ret = R.sort(sort)(ret);

    const institutions = [];
    for (const v of ret) {
      if (!institutions[v.id] && !ctx.isEmpty(v)) {
        institutions[v.id] = v;
      }
    }

    let results = [];
    for (const v of institutions) {
      if (!ctx.isEmpty(v)) {
        results.push(v);
      }
    }

    results = R.sort(sort)(results);

    if (results.length <= (page - 1) * 10) {
      return { count: 0, rows: [] };
    }
    const end = page * 10 > results.length ? results.length : page * 10;
    return {
      count: results.length,
      rows: R.slice((page - 1) * 10, end)(results),
    };
  }

  /**
     *
     * @param {*} institution_areas 校区列表
     * @param {*} areas_list 校区距离列表
     */
  async findShortestDistanceAreas(institution_areas, areas_list) {

    const { ctx } = this;

    let ret = [];
    // const institution_lbs = await this.computeDistance(areas_list);

    const institution_lbs = areas_list;
    for (const i in institution_areas) {

      const institution_area = institution_areas[i];
      // TODO 校验经纬度
      const lbs = i < institution_lbs.length ? institution_lbs[i] : { distance: 0, duration: 0, travel_method: '' };

      const area_name = institution_area.area_name;
      const distance = lbs.distance;
      const duration = lbs.duration;
      let travel_tips = `${area_name},距我${distance}km,开车${duration}分钟`;
      if (lbs.travel_method === 'walking') {
        travel_tips = `${area_name},距我${distance}km,步行${duration}分钟`;
      }
      if (Number(distance) === 0 && Number(duration) === 0) {
        travel_tips = '暂无法计算出距离';
      }
      // area.distance = distance;
      // area.duration = duration;
      // area.travel_tips = travel_tips;

      institution_area.distance = Number(distance) === 0 ? 999999999.0 : parseFloat(distance);
      institution_area.duration = duration;
      institution_area.travel_tips = travel_tips;

      ret[i] = institution_area;
    }

    const results = [];
    ret = _.orderBy(ret, [ 'distance' ], [ 'asc' ]);
    for (const j in ret) {
      const val = ret[j];
      if (!results[val.id]) {
        results[val.id] = val;
      }
    }

    return results;
  }

  async formatInstitutions(institutions, distance = 0) {

    const { ctx } = this;
    if (!Array.isArray(institutions) || institutions.length === 0) {
      return [];
    }

    // 处理机构图片
    const p_institution_images = [];
    for (const j in institutions) {
      const institution = institutions[j];
      p_institution_images[j] = ctx.classModel.V1.CourseImages.one({ where: { type: 1, type_id: institution.id, is_cover: 1, is_video: 0 } });
    }
    const institution_images = await Promise.all(p_institution_images).then(result => { // 等待所有异步内容获取完成
      return result;
    }).catch(error => {
      ctx.failed(error);
    });

    const userCollect = await ctx.classModel.V1.CourseUserCollection.findAll({ where: { user_uuid: ctx.userUuid, is_deleted: 0 } });
    const ids = R.pluck('institution_id', userCollect);

    let ret = [];
    for (const i in institutions) {
      const institution = institutions[i];
      if (distance > 0 && distance < institution.distance * 1000) {
        continue;
      }
      // const course_areas = institution.course_areas;
      // if (!course_areas || course_areas.length === 0) continue;
      const age_tag = institution.min_age + '-' + institution.max_age + '岁';
      const build_time = moment().format('YYYY') - institution.establishment_time;
      const tags = [];
      if (institution.max_age) {
        tags.push(age_tag);
      }
      if (institution.class_type) {
        tags.push(institution.class_type);
      }
      if (Number(institution.establishment_time)) {
        tags.push('成立' + build_time + '年');
      }
      let image = institution_images[i] ? institution_images[i].image_url : '';
      // 取不到封面图就从详情图列表里选一张
      if (ctx.isEmpty(image)) {
        const tmpImage = await ctx.classModel.V1.CourseImages.one({ where: { type: 1, type_id: institution.id, is_cover: 0, is_video: 0 } });
        image = ctx.isEmpty(tmpImage) ? '' : tmpImage.image_url;
      }

      ret.push({
        id: institution.id,
        name: institution.name,
        image,
        establishment_time: institution.establishment_time,
        class_type: institution.class_type,
        teacher_count: institution.teacher_count ? institution.teacher_count : 0,
        teacher_experience: institution.teacher_experience ? institution.teacher_experience : 0,
        corner: institution.corner ? institution.corner : '',
        min_age: institution.min_age,
        max_age: institution.max_age,
        price: institution.price ? institution.price : 0,
        tags,
        area_id: institution.area_id, // 校区id TODO
        travel_tips: institution.travel_tips, // TODO
        characteristic: institution.characteristic ? institution.characteristic : '',
        distance: institution.distance,
        is_collected: ids.includes(institution.id) ? 1 : 0,
      });
    }

    ret = _.orderBy(ret, [ 'distance' ], [ 'asc' ]);
    return ret;
  }


}

module.exports = InstitutionService;
