import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Delete,
  Patch,
  Query,
} from '@nestjs/common';
import {
  ApiTags,
  ApiBearerAuth,
  ApiOperation,
  ApiProperty,
} from '@nestjs/swagger';
import { TokenData } from 'src/common/decorator/token-data.decorator';
import {
  CreateTrainDto,
  UpdateTrainDto,
  TrainService,
  UpdateStepLogDto,
  LogScoreDto,
  ProxyFetchDto,
} from '../../service/train/train.service';
import { NoAuthToken } from 'src/common/decorator/no-token.decorator';
import { DataSource } from 'typeorm';
import * as request from 'request';
import * as qs from 'qs';
const formatDate = function (date, fmt) {
  // author: meizz
  const o = {
    'M+': date.getMonth() + 1, // 月份
    'd+': date.getDate(), // 日
    'h+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds(), // 毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(
      RegExp.$1,
      (date.getFullYear() + '').substr(4 - RegExp.$1.length),
    );
  for (const k in o)
    if (new RegExp('(' + k + ')').test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length),
      );
  return fmt;
};
@ApiTags('训练管理-训练模块-训练')
@ApiBearerAuth()
// @NoAuthToken()
@Controller('train/trainModule')
export class TrainModuleController {
  constructor(
    private readonly trainService: TrainService,
    private dataSource: DataSource,
  ) {}

  /* 
    创建分类
  */
  @Post()
  @ApiOperation({ summary: '创建训练' })
  async create(
    @Body() createClassifyDto: CreateTrainDto,
    @TokenData() token: any,
  ) {
    const now = new Date();
    const nowFmt = formatDate(now, 'yyyy-MM-dd hh:mm');
    createClassifyDto.creator = createClassifyDto.updater = token.userId;
    createClassifyDto.name = nowFmt + '-' + createClassifyDto.name;
    return this.trainService.create(createClassifyDto);
  }

  @Get('')
  @ApiOperation({ summary: '获取所有训练' })
  async findAll(@Query() query: { status: number }) {
    return this.trainService.findAll(+query.status);
  }
  @Post('/proxy')
  @ApiOperation({ summary: '代理发送请求' })
  @NoAuthToken()
  async proxyFetch(@Body() datas: ProxyFetchDto) {
    // return await fetch(datas.url, {
    //   method: datas.method,
    //   // headers: {
    //   //   Accept: 'application/json',
    //   //   'Content-Type': 'application/json',
    //   // },
    //   body: JSON.stringify(datas.data),
    // }).then((res) => res.json());
    if (datas.method.toLowerCase() === 'get') {
      datas.url = datas.url + '?' + qs.stringify(datas.data);
    }
    console.log(datas);
    return new Promise((res, rej) => {
      request(
        {
          url: datas.url, //请求路径
          method: datas.method, //请求方式，默认为get
          headers: {
            //设置请求头
            'content-type': 'application/json',
          },
          body: JSON.stringify(datas.data), //post参数字符串
          auth: datas.auth,
        },
        function (error, response, body) {
          if (!error && response.statusCode === 200) {
            let allRes = '';
            try {
              allRes = JSON.parse(response.body);
            } catch (error) {
              allRes = response.body;
            }
            res(allRes);
          } else {
            rej(error);
          }
        },
      );
    });
  }
  @Get('step/:id')
  @NoAuthToken()
  @ApiOperation({ summary: '获取某个训练的所有步骤' })
  async findAllStepByTrainId(@Param('id') id: number) {
    return this.trainService.findAllStepByTrainId(+id);
  }
  @Get('analysis/step/:trainId')
  @NoAuthToken()
  @ApiOperation({ summary: '训练步骤统计信息，柱状图' })
  async analysis1(@Param('trainId') id: number) {
    const datas = await this.dataSource
      .query(`select u.name uname,u.id uid,count(1) as stepCount,ts.group as groupNum ,tol.status as status from train_operation_log tol
    left join subject_step ss on ss.id = tol.step
    left join train_settings ts  on ts.id = tol.setting 
    left join user u on u.id = ts.user
    where tol.train = ${id}
    group by u.id,ts.group,tol.status `);
    const resx = {};
    let total = 0;

    datas.forEach((item) => {
      const key = item.uid + item.groupNum;
      if (!resx[key])
        resx[key] = {
          uid: item.uid,
          name: item.uname,
          group: item.groupNum,
          count: 0,
          ok: 0,
          fail: 0,
          percent: 0,
        };
      if (item.status == 1) {
        resx[key].ok = +item.stepCount || 0;
      }
      if (item.status == 2) {
        resx[key].fail = +item.stepCount || 0;
      }
      resx[key].count += +item.stepCount || 0;
      total += +item.stepCount || 0;
    });
    const res = Object.keys(resx).reduce((prev, key) => {
      const item = resx[key];
      if (!prev[item.group]) prev[item.group] = [];
      prev[item.group].push(item);
      item.percent = Math.round((item.count / total) * 100) + '%';
      return prev;
    }, {});
    return res;
  }
  @Get('analysis/device/:trainId')
  @NoAuthToken()
  @ApiOperation({ summary: '设备操作步骤统计-饼状图' })
  async analysis2(@Param('trainId') id: number) {
    const datas = await this.dataSource
      .query(`select d.name as dname,d.id as did,count(1) as stepCount,ts.group as groupNum ,tol.status as status from train_operation_log tol
      left join subject_step ss on ss.id = tol.step
      left join train_settings ts  on ts.id = tol.setting 
      left join device d on d.id = ts.device
      where tol.train = ${id}
      group by ts.device,ts.group,tol.status `);
    const resx = {};
    let total = 0;
    datas.forEach((item) => {
      if (!resx[item.did])
        resx[item.did] = {
          did: item.did,
          name: item.dname,
          group: item.groupNum,
          count: 0,
          ok: 0,
          fail: 0,
          percent: 0,
        };
      if (item.status == 1) {
        resx[item.did].ok = +item.stepCount || 0;
      }
      if (item.status == 2) {
        resx[item.did].fail = +item.stepCount || 0;
      }
      resx[item.did].count += +item.stepCount || 0;
      total += +item.stepCount || 0;
    });
    const res = Object.keys(resx).reduce((prev, key) => {
      const item = resx[key];
      if (!prev[item.group]) prev[item.group] = [];
      prev[item.group].push(item);
      item.percent = Math.round((item.count / total) * 100) + '%';
      return prev;
    }, {});
    return res;
  }
  @Get('analysis/user/position/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-号位选择比较',
  })
  async userAnalysisPostion(@Param('uid') uid: string) {
    const data = await this.dataSource
      .query(`select * ,j.positonTimes/j.total*100 as percent from (select
        dnp.name as positionName,
        dnp.id as positionId,
        count(dnp.id) as positonTimes,
        (select count(1) from
        train_score_log tsl
      left join train_settings ts on
        ts.id = tsl.setting
      left join device d on
        d.id = ts.device
      left join device_number_position dnp on
        dnp.id = d.position
      where
        ts.user = '${uid}') as total
      from
        train_score_log tsl
      left join train_settings ts on
        ts.id = tsl.setting
      left join device d on
        d.id = ts.device
      left join device_number_position dnp on
        dnp.id = d.position
      where
        ts.user = '${uid}'
      group by
        dnp.id
      ) j`);

    return data;
  }
  @Get('analysis/user/duration/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-训练用时统计',
  })
  async userAnalysisDuration(@Param('uid') uid: string) {
    const data = await this.dataSource.query(`select
      k.title as title,
      count(1) as times
    from
      (
      select
        *,
        case
          when j.realDur<j.basic1 then '高效'
          when j.realDur>j.basic2 then '延误'
          else '标准'
        end as title
      from
        (
        select
          tol.duration as tempDura,
          tol.pause as pause,
          tol.duration as realDur,
          ss.duration * 1000 as stepDur,
          ss.duration * 1000 * 0.9 as basic1,
          ss.duration * 1000 * 1.1 as basic2
        from
          train_operation_log tol
        left join train_settings ts on
          ts.id = tol.setting
        left join subject_step ss on
          ss.id = tol.step
        where
          ts.user = '${uid}' ) j)k
    group by
      k.title`);
    let dataFmt: any = [];
    let total = 0;
    for (let index = 0; index < data.length; index++) {
      const element = data[index];
      total += +element.times;
    }
    dataFmt = data.map((item) => {
      return { ...item, percent: (+item.times / total) * 100 };
    });
    return dataFmt;
  }
  @Get('analysis/user/basic/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-基本信息（平均成绩，总体排名，训练次数）',
  })
  async userAnalysis(@Param('uid') uid: string) {
    let data: any = {};
    // const [{ avgScore, trainTimes }] = await this.dataSource
    //   .query(`select avg(tsl.score) avgScore ,count(1) trainTimes  from train_score_log tsl left join train_settings ts  on ts.id = tsl.setting
    //   where ts.user  =  '${uid}'`);
    // const [{ top }] = await this.dataSource
    //   .query(`select count(1)+1 top from (select
    //     avg(tsl.score) avgScore ,
    //     count(1) trainTimes,
    //     ts.user user
    //   from
    //     train_score_log tsl
    //   left join train_settings ts on
    //     ts.id = tsl.setting
    //   group  by ts.user) c
    //   where
    //     c.avgScore>(
    //   select
    //       avg(tsl.score) avgScore
    //   from
    //       train_score_log tsl
    //   left join train_settings ts on
    //       ts.id = tsl.setting
    //   where
    //       ts.user = '${uid}')`);
    const ressss = await this.dataSource.query(`select
      *,
      (
      select
        count(1)
      from
        (
        select
          ts.user
        from
          train_score_log tsl
        left join train_settings ts on
          ts.id = tsl.setting
        group by
          ts.user)c) as total
    from
      (
      select
        1 top,
        avg(tsl.score) avgScore ,
        count(1) trainTimes,
        (case
          when avg(tsl.score) <60 then '差'
          when avg(tsl.score) <90 then '良'
          else '优'
        end) as level
      ,
        ts.user as uid
      from
        train_score_log tsl
      left join train_settings ts on
        ts.id = tsl.setting
      group by
        ts.user) c
    where
      c.uid = '${uid}'`);
    if (ressss.length > 0) {
      const [{ top, avgScore, trainTimes, level, total }] = ressss;
      // 平均成绩
      data.avgScore = +avgScore;
      // 训练次数
      data.trainTimes = +trainTimes;
      // 按平均分数排名
      data.top = +top;
      // 总人数s
      data.total = +total;
      // 综合平等等级
      data.level = level;
    } else {
      data = {
        avgScore: 0,
        trainTimes: '无',
        top: '无',
        total: '无',
        level: '无',
      };
    }

    return data;
  }
  @Get('analysis/user/scoreLine/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-科目训练历史成绩-折线图',
  })
  async userAnalysisScoreLine(@Param('uid') uid: string) {
    const data = await this.dataSource.query(`select
      tsl.score,
      t.name as tname,
      t.id as tid,
      s.id as sid,
      s.name as sname
    from
      train_score_log tsl
    left join train_settings ts on
      ts.id = tsl.setting
    left join train t on
      t.id = tsl.train
      left join subject s on s.id = t.subject 
    where ts.user = '${uid}'
      order by tsl.id asc`);

    return data;
  }
  @Get('analysis/user/positionScore/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-号位成绩比较-柱状图',
  })
  async userAnalysisPosition(@Param('uid') uid: string) {
    const data = await this.dataSource.query(`select
      dnp.name as posName,
      dnp.id as posId,
      tsl.score  as score,
      t.id as trainId,
      t.name as trainName
    from
      train_score_log tsl
    left join train_settings ts on
      ts.id = tsl.setting
      left join train t on t.id = ts.train 
    left join device d on
      d.id = ts.device
    left join device_number_position dnp on dnp.id = d.position
    where
      ts.user = '${uid}'`);
    return data;
  }
  @Get('analysis/user/subjectScore/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-所有训练场次科目成绩统计-柱状图',
  })
  async userAnalysisSubjectScore(@Param('uid') uid: string) {
    const data = await this.dataSource.query(`select
    tsl.score  as score,
    t.id as trainId,
    t.name as trainName,
    s.name as subjectName,
    s.id as subjectId
  from
    train_score_log tsl
  left join train_settings ts on
    ts.id = tsl.setting
    left join train t on t.id = ts.train 
    left join subject s  on s.id = t.subject 
  left join device d on
    d.id = ts.device
  where
    ts.user = '${uid}'`);
    return data;
  }
  @Get('analysis/user/deviceOper/:uid')
  @NoAuthToken()
  @ApiOperation({
    summary: '个人成绩-设备操作正确及错误次数统计-柱状图',
  })
  async userAnalysisDeviceOper(@Param('uid') uid: string) {
    const data = await this.dataSource.query(`select
    d.name as deviceName,
    d.id as deviceId,
    tol.status as status,
    tol.duration as dur,
    ss.duration*1000 as basicDur
  from
    train_operation_log tol
  left join train_settings ts on
    ts.id = tol.setting
  left join subject_step ss on
    ss.id = tol.step
  left join device d on
    d.id = ts.device
  where
    ts.user = '${uid}'`);
    // eslint-disable-next-line prefer-const
    let data2 = {};
    data.forEach((item, ind) => {
      if (!Object.keys(data2).includes(item.deviceId + '')) {
        data2[item.deviceId + ''] = {
          deviceName: item.deviceName,
          ok: 0,
          fail: 0,
          delay: 0,
          total: 0,
        };
      }
      data2[item.deviceId].total += 1;
      if (+item.status == 1) {
        data2[item.deviceId].ok += 1;
      } else if (+item.basicDur < +item.dur) {
        data2[item.deviceId].delay += 1;
      } else if (+item.status == 2) {
        data2[item.deviceId].fail += 1;
      }
    }, {});
    return data2;
  }

  @Get('analysis/subject/posAvgScore/:subjectId')
  @NoAuthToken()
  @ApiOperation({
    summary: '科目成绩-各班组各号位平均成绩统计-柱状图',
  })
  async posAvgScore(@Param('subjectId') subjectId: number) {
    const subId = +subjectId;
    let data = await this.dataSource.query(`select
    o.id as orgId,
    o.name as orgName,
    -- 	u.id as uId,
    -- 	u.name as uName,
    -- 	tsl.score as score,
    dnp.id as posId,
    dnp.name as posName,
    avg(tsl.score) as avgScore
  from
    train_score_log tsl
  left join train_settings ts on
    ts.id = tsl.setting
  left join train t on
    t.id = tsl.train
    left join subject s  on s.id = t.subject 
  left join device d on
    d.id = ts.device
  left join device_number_position dnp on
    dnp.id = d.position
  left join user u on
    u.id = ts.user
  left join org o on
    o.id = u.org_id
  where s.id = ${subId}
  group by
    dnp.id,
    o.id`);
    data = data.map((item) => {
      return item;
    });
    return data;
  }
  @Get('analysis/subject/posAvgDuration/:subjectId')
  @NoAuthToken()
  @ApiOperation({
    summary: '科目成绩-各班组平均操作用时统计-柱状图',
  })
  async posAvgDuration(@Param('subjectId') subjectId: number) {
    const subId = +subjectId;
    let data = await this.dataSource.query(`select
    o.id as orgId,
    o.name as orgName,
    -- 	u.id as uId,
    -- 	u.name as uName,
    -- 	tsl.score as score,
    dnp.id as posId,
    dnp.name as posName,
    avg(tol.duration) avgDur
  from
    train_operation_log tol  
  left join train_settings ts on
    ts.id = tol.setting
  left join train t on
    t.id = tol.train
    left join subject s  on s.id = t.subject 
  left join device d on
    d.id = ts.device
  left join device_number_position dnp on
    dnp.id = d.position
  left join user u on
    u.id = ts.user
  left join org o on
    o.id = u.org_id
  where s.id = ${subId}
  group by
    dnp.id,
    o.id`);
    data = data.map((item) => {
      return item;
    });
    return data;
  }
  @Get('analysis/subject/posAvgOperation/:subjectId')
  @NoAuthToken()
  @ApiOperation({
    summary: '科目成绩-不同班组在不同号位上操作步骤的统计-柱状图',
  })
  async posAvgOperation(@Param('subjectId') subjectId: number) {
    const subId = +subjectId;
    let data = await this.dataSource.query(`
    select
	o.id as orgId,
	o.name as orgName,
	dnp.id as posId,
	dnp.name as posName,
	count(tol.status = 1 or null) as okCount,
	count(tol.status = 2 or null)  as failCount,
	count(1) as allCount
  from
    train_operation_log tol  
  left join train_settings ts on
    ts.id = tol.setting
  left join train t on
    t.id = tol.train
    left join subject s  on s.id = t.subject 
  left join device d on
    d.id = ts.device
  left join device_number_position dnp on
    dnp.id = d.position
  left join user u on
    u.id = ts.user
  left join org o on
    o.id = u.org_id
  where s.id = ${subId}
  group by
    dnp.id,
    o.id`);
    data = data.map((item) => {
      return item;
    });
    return data;
  }

  @Get('details/:id')
  @NoAuthToken()
  @ApiOperation({ summary: '获取某个训练设置信息' })
  async deatils(@Param('id') id: number) {
    return this.trainService.deatils(+id);
  }

  /* 
    更新训练状态
  */
  @Patch('status/:id')
  @ApiOperation({
    summary: '更新训练状态',
  })
  async updateStatus(
    @Param('id') id: string,
    @Body() updateData: UpdateTrainDto,
  ) {
    return this.trainService.update(+id, updateData);
  }
  /* 
    更新分类
  */
  @Patch('log/:id')
  @ApiOperation({
    summary: '更新步骤记录数据（步骤完成、错误）用时、暂停时间等（id为步骤ID）',
  })
  async update(
    @Param('id') id: string,
    @Body() updateStepLogDto: UpdateStepLogDto,
  ) {
    return this.trainService.logStep(+id, updateStepLogDto);
  }

  /* 
   删除所有训练数据
 */
  @Delete('all')
  @ApiOperation({ summary: '删除所有训练' })
  async removeAll() {
    return this.trainService.removeAll();
  }
  /* 
    删除单个训练数据
  */
  @Delete(':id')
  @ApiOperation({ summary: '删除训练' })
  async remove(@Param('id') id: string) {
    return this.trainService.remove(+id);
  }

  @Post('score/:trainId')
  @ApiOperation({ summary: '保存成绩' })
  async logScore(
    @Param('trainId') trainId: number,
    @Body() data: LogScoreDto[],
    @TokenData() token: any,
  ) {
    const newD = data.map((i) => ({
      ...i,
      creator: token.userId,
      updater: token.userId,
    }));
    return this.trainService.logScore(+trainId, newD);
  }
  @Get('score/:trainId')
  @NoAuthToken()
  @ApiOperation({ summary: '获取成绩' })
  async getScore(@Param('trainId') trainId: number) {
    return this.trainService.getScore(+trainId);
  }
}
