import { Connection, Repository } from 'typeorm';
import { Injectable, Logger } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import { Video } from '../../domains/video/video.entities';
import { TaskStatusType, TaskType, VideoTask } from './video-task.entities';
import { RedisProvider } from '../../infrastructures/redis-provider.service';
import * as _ from 'lodash';
const FormData = require('form-data');
const fetch = require('node-fetch');
const fs = require('fs');
const md5File = require('md5-file');
const md5 = require('md5');
const request = require('request');
const logger = new Logger('VideoTaskService');

@Injectable()
export class VideoTaskService {
  private readonly videoTaskRepository: Repository<VideoTask>;
  private readonly videoRepository: Repository<Video>;

  constructor(
    @InjectConnection() private readonly connection: Connection,
    private readonly redis: RedisProvider,
  ) {
    this.videoTaskRepository = connection.getRepository(VideoTask);
    this.videoRepository = connection.getRepository(Video);
  }

  async add(
    userId: number,
    url: string,
    taskStatus: keyof typeof TaskStatusType,
    taskType: keyof typeof TaskType,
  ): Promise<VideoTask[]> {
    const entity = this.videoTaskRepository.create({
      userId,
      url,
      taskStatus,
      taskType,
    });
    return this.videoTaskRepository.save([entity]);
  }

  async queryToTranslate(
    take: number,
    taskStatus: keyof typeof TaskStatusType,
  ): Promise<VideoTask[]> {
    const result = this.videoTaskRepository.find({
      order: { createdAt: 'DESC' },
      where: {
        taskStatus,
      },
      take,
    });
    return result;
  }

  async translated(taskId: string, url: string) {
    return this.videoTaskRepository.update({ taskId }, { url, taskStatus: 'translated' });
  }

  async submit(id: number, taskId: string) {
    return this.videoTaskRepository.update({ id }, { taskId, taskStatus: 'submit' });
  }

  async submitTasks() {
    const redLock = this.redis.redLock;
    await redLock
      .lock('locks:submitTask', 180000)
      .then(lock => {
        logger.log('get lock submitTask');
        this.processTasks(lock);
      })
      .catch(err => {
        console.error('getLock err:', err.stack);
      });
    return;
    // return this.videoBarrageService.add(body.userId, body.videoId, body.time, body.text);
  }

  async processTasks(lock) {
    const tasks = await this.videoTaskRepository.find({
      order: { createdAt: 'ASC' },
      where: { taskStatus: 'created' },
    });
    if (tasks && tasks.length > 0) {
      for (const task of tasks) {
        await this.processTask(task, lock);
      }
      logger.log('process video code convert');
    }
    return;
  }

  async processTask(task: VideoTask, lock: any) {
    const filePath = '/Users/tanxiao/Downloads/test3.mp4';
    const fileFullName = filePath.substring(filePath.lastIndexOf('/') + 1);
    let ext = fileFullName.substring(fileFullName.indexOf('.'));
    const fileName = fileFullName.replace(`${ext}`, '');
    ext = ext.replace('.', '');
    // 检查文件是否已存在
    // const hash = md5File.sync(filePath);
    const hash = '3459a56b7e04dd6cde5b5accba36142c';
    const dateTime = Date.now();
    const md5checkUrl = `http://ppvod服务器ip:2000/uploads?status=md5Check&md5=${hash}&name=${fileName}&_=${dateTime}`;
    console.log('md5checkUrl', md5checkUrl);
    fetch(md5checkUrl)
      .then(res => res.json())
      .then(json => {
        // 返回json:
        // {"ifExist":1,"duration":"00:00:30","title":"test1","path":"t1iwmRgt",
        // "pic":"http://ppvod服务器ip:2100/20190419/t1iwmRgt/1.jpg",
        // "pics":"http://ppvod服务器ip:2100/20190419/t1iwmRgt/pic/all.jpg",
        // "size":0,"gif":"http://ppvod服务器ip:2100/20190419/t1iwmRgt/1.gif",
        // "qr":"http://ppvod服务器ip:2100/qrapi/mn4ByURd9OIl7O7N",
        // "orgfile":"http://ppvod服务器ip:2100/20190419/t1iwmRgt.mp4",
        // "url":"http://ppvod服务器ip:2100/20190419/t1iwmRgt/index.m3u8",
        // "mp4":"http://ppvod服务器ip:2100/20190419/t1iwmRgt/mp4/t1iwmRgt.mp4",
        // "share":"http://ppvod服务器ip:2100/share/mn4ByURd9OIl7O7N"}
        console.log(json);
        // 如果文件已存在,直接更新任务为已完成
        if (json.ifExist) {
          const qr = json.qr;
          const shareId = qr.substring(qr.lastIndexOf('/') + 1);
          console.log('shareId:', shareId);
          console.log('video exist:', fileFullName);
          // TODO 改为批量任务处处理
          lock.unlock().catch(err => {
            console.error(err);
          });
        } else {
          // 处理文件上传
          // 文件分片
          const chunkSize = 10 * 1024 * 1024;
          const fs = require('fs');
          const states = fs.statSync(filePath);
          const fileSize = states.size;
          const lastModifiedDate = new Date(states.mtime).toISOString();
          console.log('states.mtime:', states.mtime);
          console.log('fileLastModifiedDate:', lastModifiedDate);
          console.log('fileSize:', fileSize);
          console.log('fileFullName', fileFullName);
          // TODO fileType video/ 先写死
          // const md5Encoder = require('md5');
          // const uniqueFileName = md5Encoder(
          //   `the_user${fileName}video/${ext}${fileLastModifiedDate}${fileSize}`,
          // );
          const uniqueFileName = 'f4a216698d4188485f5ecaa4fb34a412';
          // var userInfo = { userId: 'the_user', md5: hash, uniqueFileName: '' }; //用户会话信息
          // foo.txt => hello
          const formData = new FormData();
          const jobj = {
            userId: 'the_user',
            md5: hash,
            uniqueFileName,
            name: fileName,
            type: 'video/mp4',
            lastModifiedDate,
            size: fileSize,
            ext,
            fileName,
          };
          this.chunkToUpload(lock, filePath, 0, chunkSize, 0, jobj, dateTime + 1);
        }
      });
  }

  chunkToUpload(
    lock: any,
    filePath: string,
    chunkIndex: number,
    chunkSize: number,
    processedSize: number,
    jObj: any,
    dateTime: number,
  ) {
    console.log(`执行chunIndex${chunkIndex}.已发送完成${processedSize}`);
    const readchunk = require('read-chunk');
    const fileSize = _.get(jObj, 'size');
    console.log(`formData:${JSON.stringify(jObj)}`);
    const ext = _.get(jObj, 'ext');
    const fileName = _.get(jObj, 'name');
    console.log('fileName:', fileName);
    const userId = _.get(jObj, 'userId');
    const hash = _.get(jObj, 'md5');
    const lastModifiedDate = _.get(jObj, 'lastModifiedDate');
    const uniqueFileName = _.get(jObj, 'uniqueFileName');
    const chunksCount = Math.ceil(fileSize / chunkSize);
    const currentSize = Math.min(chunkSize, fileSize - chunkSize * chunkIndex);
    console.log('currentSize:', currentSize);
    console.log('chunkIndex === chunksCount: ', chunkIndex === chunksCount);
    if (chunkIndex === chunksCount) {
      console.log('已上传完所有切片，执行merge请求--');
      const mergeUrl = `http://ppvod服务器ip:2000/uploads?status=chunksMerge&name=${uniqueFileName}&chunks=${chunksCount}&ext=${ext}&fileoldname=${fileName}&md5=${hash}&_=${dateTime +
        1}`;
      console.log('mergeUrl:', mergeUrl);
      fetch(mergeUrl)
        .then(res => res.json())
        .then(json => {
          console.log('mergeResp:', json);
          lock.unlock().catch(err => {
            console.error(err);
          });
        });
      return;
    }
    const chunk = readchunk.sync(filePath, processedSize, currentSize);
    // const readStream = fs.createReadStream(filePath, {
    //   autoClose: false,
    //   start: chunkIndex * chunkSize,
    //   end: chunkIndex * chunkSize + chunkSize,
    // });
    const chunkCheckUrl = `http://ppvod服务器ip:2000/uploads?status=chunkCheck&name=${uniqueFileName}&chunkIndex=${chunkIndex}&size=${currentSize}&_=${dateTime +
      1}`;
    console.log('chunkCheckUrl:', chunkCheckUrl);
    fetch(chunkCheckUrl)
      .then(res => res.json())
      .then(json => {
        // 如果分片不存在,则上传此分片
        if (!json.isExist) {
          console.log(`文件${fileName}:分片${chunkIndex}不存在，可上传当前分片`);
          this.upload(lock, jObj, chunk, filePath, chunkSize, processedSize, chunkIndex, dateTime);
        } else {
          console.log(`文件${fileName}:分片${chunkIndex}已存在，跳过当前分片`);
          this.chunkToUpload(
            lock,
            filePath,
            chunkIndex + 1,
            chunkSize,
            processedSize + chunkSize,
            jObj,
            dateTime,
          );
        }
      });
  }

  upload(
    lock: any,
    jObj: any,
    chunk: any,
    filePath: string,
    chunkSize: number,
    processedSize: number,
    chunkIndex: number,
    dateTime: number,
  ) {
    const readchunk = require('read-chunk');
    const fileSize = _.get(jObj, 'size');
    const ext = _.get(jObj, 'ext');
    const fileName = _.get(jObj, 'name');
    const userId = _.get(jObj, 'userId');
    const hash = _.get(jObj, 'md5');
    const lastModifiedDate = _.get(jObj, 'lastModifiedDate');
    const uniqueFileName = _.get(jObj, 'uniqueFileName');
    const chunksCount = Math.ceil(fileSize / chunkSize);
    const currentSize = Math.min(chunkSize, fileSize - chunkSize * chunkIndex);
    const r = request.post('http://ppvod服务器ip:2000/uploads', (err, httpResponse, body) => {
      const statusCode = httpResponse.statusCode;
      logger.log('httpResponse:', httpResponse);
      this.chunkToUpload(
        lock,
        filePath,
        chunkIndex + 1,
        chunkSize,
        processedSize + currentSize,
        jObj,
        dateTime,
      );
    });
    const formData = r.form();
    // const formData = new FormData();
    formData.append('userId', userId);
    formData.append('md5', hash);
    formData.append('uniqueFileName', uniqueFileName);
    formData.append('name', fileName);
    formData.append('type', 'video/mp4');
    formData.append('lastModifiedDate', lastModifiedDate);
    formData.append('size', fileSize);
    formData.append('ext', ext);
    formData.append('chunks', `${chunksCount}`);
    formData.append('chunk', `${chunkIndex}`);
    formData.append('file', chunk, fileName);
    formData.append('id', 'WU_FILE_1');
    console.log('buffer----', chunk.byteLength);
    const sBoundary = `----WebKitFormBoundary${Date.now().toString(16)}`;
    const headers = `multipart/form-data; boundary=${sBoundary}`;
    // formData.submit(
    //   {
    //     host: 'ppvod服务器ip',
    //     port: 2000,
    //     path: '/uploads',
    //     headers: { 'Content-Type': headers },
    //   },
    //   (err, res) => {
    //     if (err) {
    //       console.log('err:', err.stack);
    //     }
    //     console.log('res:-----', res.statusCode);
    //     const statusCode = res.statusCode;
    //     if (statusCode === 200) {
    //       this.chunkToUpload(
    //         lock,
    //         filePath,
    //         chunkIndex + 1,
    //         chunkSize,
    //         processedSize + currentSize,
    //         jObj,
    //         dateTime,
    //       );
    //     }
    //   },
    // );
  }
}
