import { Inject, Provide, Config } from '@midwayjs/core';
import { get } from 'lodash';
import { Context } from '@midwayjs/koa';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { ServiceError, ErrorCode } from '../error/service.error';
import dayjs = require('dayjs');
import { DictDataService } from './system/dictData.service';
import { Equal, Repository } from 'typeorm';
import { Achievement } from '../entity/platform/achievement.entity';
import { Company } from '../entity/users/company.entity';
import { Supply } from '../entity/platform/supply.entity';
import { Project } from '../entity/platform/project.entity';
import { Demand } from '../entity/platform/demand.entity';
import { UserService } from './system/user.service';
import * as mappings from '../public/importMapping';
import * as Excel from 'exceljs';
import * as Path from 'path';
import * as fs from 'fs';
import { User } from '../entity/system/user.entity';
import { CompanyYear } from '../entity/users/companyYear.entity';
/**
 * 工具类服务,为其他地方提供一些通用的函数
 */
@Provide()
export class UtilService {
  @Inject()
  ctx: Context;
  @Inject()
  userService: UserService;

  @InjectEntityModel(User)
  userModel: Repository<User>;
  @InjectEntityModel(Achievement)
  achievementModel: Repository<Achievement>;
  @InjectEntityModel(Project)
  projectModel: Repository<Project>;
  @InjectEntityModel(Demand)
  demandModel: Repository<Demand>;
  @InjectEntityModel(Supply)
  supplyModel: Repository<Supply>;
  @InjectEntityModel(Company)
  companyModel: Repository<Company>;
  @InjectEntityModel(CompanyYear)
  yModel: Repository<CompanyYear>;
  @Inject()
  dictDataService: DictDataService;

  @Config('PathConfig.path')
  path;

  // 导出
  async toExport(query) {
    const { table, config, user } = query;
    const nowDate = new Date().getTime();
    const filename = `产学研用导出-${table}-${nowDate}.xlsx`;
    const path = this.path;
    if (!path) {
      throw new ServiceError('服务端没有设置存储路径');
    }
    if (!fs.existsSync(path)) {
      // 如果不存在文件夹,就创建
      this.mkdir(path);
    }
    try {
      let info = {};
      if (user) info = { where: { user: Equal(user) } };
      const targetModel = this[`${table}Model`];
      const data = await targetModel.find(info);
      const workbook = new Excel.Workbook();
      const sheet = workbook.addWorksheet('sheet1');
      // 根据前端传回来的设置和顺序,将表头先塞进去
      const meta = config.map(i => i.label);
      sheet.addRow(meta);
      let arr = [];
      for (const d of data) {
        arr = [];
        for (const c of config) {
          const { mark, model, code } = c;
          if (mark === 'tags') {
            if (d[model]) d[model] = arr.push(d[model].join(','));
            else arr.push(d[model]);
          } else if (mark === 'area') {
            if (d[model]) d[model] = arr.push(d[model].join('-'));
            else arr.push(d[model]);
          } else if (mark === 'dict') {
            const req = await this.dictDataService.query({ code, is_use: '0' }, {});
            if (req.data) {
              const selected = req.data.find(f => f.value === d[model]);
              if (selected) {
                d[model] = get(selected, 'label');
                arr.push(d[model]);
              } else arr.push(d[model]);
            } else arr.push(d[model]);
          } else if (mark === 'time') {
            if (d.start_time && d.end_time) {
              arr.push((d[model] = `${d.start_time}-${d.end_time}`));
            } else arr.push(d[model]);
          } else arr.push(d[model]);
        }
        sheet.addRow(arr);
      }
      // 生成excel
      const filepath = `${path}${filename}`;
      if (data.length <= 0) return;
      await workbook.xlsx.writeFile(filepath);
      return `/files/cxyy/export/${filename}`;
    } catch (error) {
      console.log(error);
    }
  }
  // 创建文件夹
  mkdir(dirname) {
    if (fs.existsSync(dirname)) {
      return true;
    }
    if (this.mkdir(Path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }

  randomStr(len = 6) {
    return Math.random().toString(36).slice(-len);
  }

  /**
   * 成果
   * @param {Object} rows excel数据
   */
  async achievement(rows) {
    const mappingList = mappings.achievement;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    const user_id = this.ctx.user.id;
    for (const [index, i] of result.entries()) {
      // 根据 成果名称 查重
      const { name } = i;
      const data = await this.achievementModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.achievementModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}出现错误！！！`);
        }
      } else {
        try {
          await this.achievementModel.insert({ ...i, user: user_id, status: '0' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }

  /**
   * 项目
   * @param {Object} rows excel数据
   */
  async project(rows) {
    const mappingList = mappings.project;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    const user_id = this.ctx.user.id;
    for (const [index, i] of result.entries()) {
      // 根据 项目名称 查重
      const { name } = i;
      const data = await this.projectModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.projectModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}字段出现错误！！！`);
        }
      } else {
        try {
          await this.projectModel.insert({ ...i, user: user_id, status: '0' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }
  /**
   * 需求
   * @param {Object} rows excel数据
   */
  async demand(rows) {
    const mappingList = mappings.demand;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    const user_id = this.ctx.user.id;
    for (const [index, i] of result.entries()) {
      // 根据 需求名称 查重
      const { name } = i;
      const data = await this.demandModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.demandModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}出现错误！！！`);
        }
      } else {
        try {
          await this.demandModel.insert({ ...i, user: user_id, status: '0' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }
  /**
   * 供给
   * @param {Object} rows excel数据
   */
  async supply(rows) {
    const mappingList = mappings.supply;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    const user_id = this.ctx.user.id;
    for (const [index, i] of result.entries()) {
      // 根据 供给名称 查重
      const { name } = i;
      const data = await this.supplyModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.supplyModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}出现错误！！！`);
        }
      } else {
        try {
          await this.supplyModel.insert({ ...i, user: user_id, status: '0' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }

  /**
   * 企业
   * @param {Object} rows excel数据
   */
  async company(rows) {
    const mappingList = mappings.company;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    for (const [index, i] of result.entries()) {
      // 根据 企业名称 查重
      const { name, industry } = i;
      const data = await this.companyModel.findOne({ where: { name: Equal(name) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.companyModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}出现错误！！！`);
        }
      } else {
        try {
          const userInfo = await this.userModel.insert({ account: name, nick_name: name, password: '123456', industry: [industry], gender: '0', role: ['User', 'Company'], status: '1' });
          const id = get(userInfo, 'identifiers.0.id');
          await this.companyModel.insert({ ...i, user: id, status: '1', is_show: '1' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }

  /**
   * 企业年度
   * @param {Object} rows excel数据
   */
  async companyYear(rows) {
    const mappingList = mappings.companyYear;
    const result = await this.dealRows(rows, mappingList);
    const errorList = [];
    // 需要查看是否有人,有人更新数据,没人添加数据
    for (const [index, i] of result.entries()) {
      const { company, year } = i;
      const data = await this.yModel.findOne({ where: { company: Equal(company), year: Equal(year) } });
      if (data && data.id) {
        try {
          i.id = data.id;
          await this.yModel.update({ id: data.id }, i);
        } catch (error) {
          errorList.push(`修改第${index + 1}条${name}出现错误！！！`);
        }
      } else {
        try {
          const companyInfo = await this.companyModel.findOne({ where: { id: Equal(company) } });
          const userInfo = await this.userService.fetch({ id: companyInfo.user });
          const id = get(userInfo, 'id');
          await this.yModel.insert({ ...i, user: id, status: '1', is_use: '0' });
        } catch (error) {
          const namek = Object.keys(error.errors)[0];
          const mapping = mappingList.find(i => i.field === namek);
          errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误！！！`);
        }
      }
    }
    return { result: result.length, errorList };
  }
  /**
   * 处理excel传来的数据
   * @param {Array} rows excel数据,二维数组
   * @param {Object} mappingList 设置的某个映射
   * @return {Array} result 数据
   */
  async dealRows(rows, mappingList) {
    const result = [];
    const user = this.ctx.user;
    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
    for (let i = 0; i < rows.length; i++) {
      const rowData = rows[i];
      const obj = { user: user.id };
      for (let k = 0; k < rowData.length; k++) {
        let val = rowData[k];
        if (val === null) continue;
        if (typeof val === 'object' && val !== null) {
          const richText = get(val, 'richText');
          if (richText) {
            let texts = '';
            // 使用map提取name字段，然后检查是否为undefined
            // eslint-disable-next-line array-callback-return
            const mappedNames = richText.map(item => {
              // 判断字段是否存在
              if ('text' in item) {
                return item.text;
              }
            });
            // 过滤掉null或undefined的值
            const filteredNames = mappedNames.filter(text => text !== null && text !== undefined);
            // 拼接字符串
            texts = filteredNames.join('');
            val = texts;
          }
        }
        const mapping = mappingList.find(f => f.index === k);
        if (mapping) {
          const { field, type } = mapping;
          if (type) val = await this.dealTypeValue(mapping, val);
          obj[field] = val;
        }
      }
      result.push(obj);
    }
    return result;
  }

  /**
   * 转换数据
   * @param {Object} mapping 当前要处理的映射
   * @param {any} val excel值
   * @return {any} result 转换后的数据
   */
  async dealTypeValue(mapping, val) {
    const { type, code } = mapping;
    let result;
    if (type === 'date') {
      // 判断日期对不对,经过moment处理下
      const mobj = dayjs(val);
      if (mobj.isValid()) {
        result = mobj.format('YYYY-MM-DD');
      }
    } else if (type === 'dict') {
      const req = await this.dictDataService.query({}, { code });
      if (req.data) {
        const selected = req.data.find(f => f.label === val);
        if (selected) result = get(selected, 'value');
      }
    } else if (type === 'area') {
      if (val) result = val.split('-');
    } else if (type === 'number') {
      if (val === 0) {
        result = val;
      } else {
        if (val) result = parseInt(val) || 0;
      }
    } else if (type === 'id') {
      if (val) {
        const company = await this.companyModel.findOne({ where: { name: Equal(val) } });
        if (company) result = get(company, 'id');
        else result = val;
      } else {
        result = val;
      }
    }
    return result;
  }

  nameToFunction(name) {
    const obj = {
      成果: 'achievement',
      项目: 'project',
      需求: 'demand',
      供给: 'supply',
      企业: 'company',
      企业年度: 'companyYear',
    };
    return get(obj, name);
  }
}
