import { Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { ContactApply } from '../../entity/users/contactApply.entity';
import { BaseServiceV2 } from '../../frame/BaseServiceV2';
import { compact, get, head, isArray, uniq } from 'lodash';
import { Demand } from '../../entity/platform/demand.entity';
import { Supply } from '../../entity/platform/supply.entity';
import { Expert } from '../../entity/users/expert.entity';
import { User } from '../../entity/system/user.entity';
import { ErrorCode, ServiceError } from '../../error/service.error';
import { MessageUserType } from '../../public/var';
import { Admin } from '../../entity/system/admin.entity';
import { Design } from '../../entity/platform/design.entity';
import { Incubator } from '../../entity/users/incubator.entity';
import { Sector } from '../../entity/platform/sector.entity';
import { Project } from '../../entity/platform/project.entity';
import { Achievement } from '../../entity/platform/achievement.entity';

@Provide()
export class ContactApplyService extends BaseServiceV2 {
  getQueryColumnsOpera(): object {
    return {};
  }
  @InjectEntityModel(Design)
  design: Repository<Design>;

  @InjectEntityModel(ContactApply)
  model: Repository<ContactApply>;

  @InjectEntityModel(Demand)
  demand: Repository<Demand>;
  @InjectEntityModel(Supply)
  supply: Repository<Supply>;
  @InjectEntityModel(Project)
  project: Repository<Project>;
  @InjectEntityModel(Achievement)
  achievement: Repository<Achievement>;
  @InjectEntityModel(Incubator)
  incubator: Repository<Incubator>;
  @InjectEntityModel(Sector)
  sector: Repository<Sector>;

  @InjectEntityModel(Expert)
  expert: Repository<Expert>;

  @InjectEntityModel(User)
  user: Repository<User>;
  @InjectEntityModel(Admin)
  admin: Repository<Admin>;
  

  /**不需要对象用户和匹配度计算数据类型:孵化基地,产业集群 */
  skipCheckList = ['incubator', 'sector'];
  /**
   * 审核成功后,返回给申请人申请的 联系方式
   * @param {number} id 申请id
   * @param {object} inputContacts 产业集群需要填写的联系人和联系电话
   */
  async successMessage(id, inputContacts) {
    const apply = await this.model.createQueryBuilder().where(`id =:id`, { id }).getOne();
    // 抛异常,未找到数据
    if (!apply) throw new ServiceError(ErrorCode.DATA_NOT_FOUND);
    const source = get(apply, 'source');
    const source_id = get(apply, 'source_id');
    const mqTarget = get(apply, 'apply_user');
    const applyUserData = await this.getUserData(mqTarget);
    const mqTargetUserNickName = get(applyUserData, 'nick_name');
    let sourceStr = this.getSourceZh(source);
    const otherData = await this.searchCompleteData(source, source_id);
    const sourceData = get(otherData, 'sourceData');
    const sourcePropValue = get(sourceData, 'name');
    let contacts = {};
    if (source === 'sector') contacts = inputContacts;
    else contacts = this.getContactObject(otherData, source);
    let msgStr = `您通过 ${sourceStr}数据 ${sourcePropValue ? `- ${sourcePropValue}` : ''} 获取对方联系方式的申请已通过.`;
    // 拼接联系方式
    const person = get(contacts, 'person');
    if (person) msgStr = `${msgStr} 联系人: ${person};`;
    const phone = get(contacts, 'phone');
    if (phone) msgStr = `${msgStr} 联系电话: ${phone};`;
    const email = get(contacts, 'email');
    if (email) msgStr = `${msgStr} 邮箱: ${email}`;
    const to = [{ user: mqTarget, user_type: MessageUserType.USER, user_nick_name: mqTargetUserNickName, is_read: '0' }];
    const msgObj = { content: msgStr, to, type: '0' };
    return msgObj;
  }

  /**处理数据,将显示内容取出 */
  async dealData(data) {
    let list = [];
    // 统一组织成数组形式处理,如果只是1条数据,那最后head取出返回即可
    const isArr = isArray(data);
    if (isArr) list = data;
    else list.push(data);
    /**需要组织 apply_user , target_user 的用户数据的name; source需要转换成中文, source_id需要取出name; exam_admin:需要转换成管理员昵称*/
    let auIds = list.map(i => i.apply_user); // 提取apply_user为一维数组Array<number>
    auIds = compact(uniq(auIds)); // 清除假值(去重数组)
    let tuIds = list.map(i => i.target_user);
    tuIds = compact(uniq(tuIds));
    const uIds = uniq([...auIds, ...tuIds]); // 两个ids结合,去重,一次都查出来
    const userList = await this.user.createQueryBuilder().where(`id IN (:...ids)`, { ids: uIds }).getMany();
    const returnData = [];
    for (const i of list) {
      const obj: any = {};
      // apply_user
      obj.apply_user = get(i, 'apply_user');
      const auInfo = userList.find(f => f.id === i.apply_user);
      if (auInfo) obj.apply_user_name = get(auInfo, 'nick_name');
      // target_user
      obj.target_user = get(i, 'target_user');
      const tuInfo = userList.find(f => f.id === i.target_user);
      if (tuInfo) obj.target_user_name = get(tuInfo, 'nick_name');
      // source
      obj.source = get(i, 'source');
      const sourceZh = this.getSourceZh(get(i, 'source'));
      if (sourceZh) obj.sourceZh = sourceZh;
      obj.source_id = get(i, 'source_id');
      const otherData = await this.searchCompleteData(get(i, 'source'), get(i, 'source_id'));
      const sourceData = get(otherData, 'sourceData');
      const propName = this.getSourceProp(get(i, 'source'));
      const sourcePropValue = get(sourceData, propName);
      if (sourcePropValue) obj.source_name = sourcePropValue;
      // exam_admin
      if (get(i, 'exam_admin')) {
        obj.exam_admin = get(i, 'exam_admin');
        const adminInfo = await this.admin
          .createQueryBuilder()
          .where(`id =:id`, { id: get(i, 'exam_admin') })
          .getOne();
        if (adminInfo) obj.exam_admin_name = get(adminInfo, 'nick_name');
      }
      // status
      obj.status = get(i, 'status');
      // id
      obj.id = get(i, 'id');
      returnData.push(obj);
    }
    if (isArr) return returnData;
    else return head(returnData);
  }

  /**
   * 查询本用户可审批的数据来源
   */
  async checkUserSourceRange() {
    const user = get(this.ctx, 'user', {});
    const is_super = get(user, 'is_super');
    const config = await this.design.createQueryBuilder().getOne();
    if (!config) throw new ServiceError(ErrorCode.DATA_NOT_FOUND);
    const setting = get(config, 'contactApplyConfig', {});
    // 超级管理员都查
    if (is_super === '0') {
      const keys = Object.keys(setting);
      return keys;
    }
    // 接下来取出部门
    const dept = get(user, 'dept');
    // 抛出异常: 本管理员无部门,无法查询预约申请
    if (!dept) throw new ServiceError(ErrorCode.CONTACTAPPLY_DEPT_NO_ADMIN);
    // 整理出本部门管理的数据来源
    const sources: Array<string> = [];
    for (const key in setting) {
      const val = setting[key];
      if (val === dept) sources.push(key);
    }
    return sources;
  }

  /**
   * 根据 数据来源 找到对应管理的部门
   * @param source 数据来源
   */
  async getSourceDept(source: string) {
    const config = await this.design.createQueryBuilder().getOne();
    if (!config) throw new ServiceError(ErrorCode.DATA_NOT_FOUND);
    const setting = get(config, 'contactApplyConfig', {});
    const dept_id = get(setting, `${source}`);
    if (!dept_id) return;
    const adminList = await this.admin.createQueryBuilder().where(`dept =:dept`, { dept: dept_id }).getMany();
    const ids = adminList.map(i => i.id);
    return ids;
  }

  /**
   * 组织数据,通知管理员进行审核
   * @param data 联系方式申请数据
   * @param adminIds 接收通知的管理员id数组
   */
  async getAdminToExamData(data, adminIds) {
    const source = get(data, 'source');
    const source_id = get(data, 'source_id');
    const otherData = await this.searchCompleteData(source, source_id);
    const sourceZh = this.getSourceZh(source);
    const applyUserData = await this.getUserData(get(data, 'apply_user'));
    const apply_userName = get(applyUserData, 'nick_name');
    const sourceData = get(otherData, 'sourceData');
    const sourcePropValue = get(sourceData, 'name');
    const content = `用户${apply_userName} 通过 ${sourceZh}数据 ${sourcePropValue ? `- ${sourcePropValue}` : ''} 申请获取联系方式!`;
    // 组织message消息数据
    const adminList = await this.admin.createQueryBuilder().where(`id IN (:...value)`, { value: adminIds }).getMany();
    const to = adminList.map(i => {
      const obj = { user: get(i, 'id'), user_nick_name: get(i, 'nick_name'), user_type: MessageUserType.ADMIN, is_read: '0' };
      return obj;
    });
    const messageData = { content, to, type: '1' };
    return messageData;
  }

  /**
   * 获取用户数据
   * @param id 用户id
   * @returns
   */
  async getUserData(id) {
    const user = await this.user.createQueryBuilder().where(`"id" = :id`, { id }).getOne();
    return user;
  }
  /**
   * 根据 apply_user ,target_user检查是否有未通过审核的数据
   * 允许重复多次申请,但是每次必须都得审核完后再申请
   * 如果有:直接返回信息;
   * 如果没有,返回继续执行
   * @param data
   */
  async checkHasApply(data) {
    const apply_user = get(data, 'apply_user');
    const target_user = get(data, 'target_user');
    const source = get(data, 'source');
    const source_id = get(data, 'source_id');
    const builder = this.model.createQueryBuilder().where(`"apply_user" = :apply_user`, { apply_user });
    if (!this.skipCheckList.includes(source)) builder.andWhere(`"target_user" = :target_user`, { target_user });
    else {
      builder.andWhere(`"source" =:source`, { source });
      builder.andWhere(`"source_id" =:source_id`, { source_id });
    }
    // const apply = await builder.andWhere(`"status" = :status`, { status: '1' }).getOne();
    // 查询是不是有其他状态的申请: 未审核,已拒绝,如果有,就根据状态返回提示语
    const othersApply = await builder.getOne();
    // 没有找到其他的申请,直接返回
    if (!othersApply) return;
    const status = get(othersApply, 'status');
    // 有没审核的申请,抛出异常
    if (status === '0') throw new ServiceError(ErrorCode.CONTACTAPPLY_HAS_APPLY_NOT_STATUS);
    // 被拒绝了也允许重新申请
    else if (status === '-1') return;
  }
  /**
   * 组织联系信息
   * 需求是先从需求中找联系方式,没有再从用户中找,其余的都直接从用户中找
   * @param data searchCompleteData的返回
   * @param source 来源
   */
  getContactObject(data, source) {
    const contacts: any = {};
    if (source === 'demand') {
      const sourceData = get(data, 'sourceData');
      if (get(sourceData, 'tel')) contacts.phone = get(sourceData, 'tel');
      if (get(sourceData, 'contacts')) contacts.person = get(sourceData, 'contacts');
    } else if (source === 'incubator') {
      const sourceData = get(data, 'sourceData');
      const person = get(sourceData, 'person');
      const phone = get(sourceData, 'person_phone');
      if (person) contacts.person = person;
      if (phone) contacts.phone = phone;
    }
    if (Object.keys(contacts).length <= 0) {
      const user = get(data, 'userData');
      if (get(user, 'phone')) contacts.phone = get(user, 'phone');
      if (get(user, 'nick_name')) contacts.person = get(user, 'nick_name');
      if (get(user, 'email')) contacts.email = get(user, 'email');
    }
    return contacts;
  }

  /**
   * 根据source和source_id,查找数据,再查找数据拥有人的信息,返回数据
   * @param source 数据来源
   * @param source_id 数据来源的id
   */
  async searchCompleteData(source, source_id) {
    let model = this[source];
    if (!model) return;
    const sourceData = await model.createQueryBuilder().where(`"id" = :id`, { id: source_id }).getOne();
    if (!sourceData) return;
    const result = { sourceData };
    const userId = get(sourceData, 'user');
    if (!userId) return result;
    const user = await this.user.createQueryBuilder().where(`"id" = :id`, { id: userId }).getOne();
    if (!user) return result;
    result['userData'] = user;
    return result;
  }
  /**
   * 数据来源中文
   * @param source 数据来源
   */
  getSourceZh(source: string) {
    let str;
    switch (source) {
      case 'demand':
        str = '需求';
        break;
      case 'supply':
        str = '供给';
        break;
      case 'project':
        str = '项目';
        break;
      case 'achievement':
        str = '成果';
        break;
      case 'incubator':
        str = '孵化基地';
        break;
      case 'sector':
        str = '产业集群';
        break;
      default:
        break;
    }
    return str;
  }
  getSourceProp(source: string) {
    let str;
    switch (source) {
      case 'demand':
        str = 'name';
        break;
      case 'supply':
        str = 'name';
        break;
      case 'project':
        str = 'name';
        break;
      case 'achievement':
        str = 'name';
        break;
      case 'incubator':
        str = 'name';
        break;
      case 'sector':
        str = 'title';
        break;
      default:
        break;
    }
    return str;
  }
}
