import { Controller } from 'egg';
import { Stream } from 'stream';
import { STATUS } from '@consts';
 const fs = require('fs');
 const path = require('path');
const unzip = require("unzip-stream");
const temp = require('temp');
const compressing = require("compressing");
const moment = require("moment");
const pump = require('mz-modules/pump');

const folderName = 'hot_update_files';
const hotUpdateAddr = `/root/${folderName}`;
const publishPath = '/root/hot_update_backup';
import {exec} from 'child_process'
import { reloadResources } from '@pubUtils/data';
import { decodeArrayStr } from '@pubUtils/util';
const sendToWormhole = require('stream-wormhole');

export default class UploadController extends Controller {

    private deleteFolder (path) {
        let files = [];
        if( fs.existsSync(path) ) {
            files = fs.readdirSync(path);
            files.forEach((file) =>{
                let curPath = path + "/" + file;
                if(fs.statSync(curPath).isDirectory()) {
                    this.deleteFolder(curPath);
                } else {
                    fs.unlinkSync(curPath);
                }
            });
            fs.rmdirSync(path);
        }
    }


  private getFileList (p: string, resultArr: Array<{path:string,name:string}>) {
      console.log(p, fs.existsSync(p))
    if( fs.existsSync(p) ) {
        let files = fs.readdirSync(p);
        console.log(p, files, resultArr);
        files.forEach((file) =>{
            let curPath = p + "/" + file;
            // console.log(curPath, fs.statSync(curPath).isDirectory())
            if(fs.statSync(curPath).isDirectory()) {
                this.getFileList(curPath, resultArr);
            } else {
                resultArr.push({
                    path: curPath,
                    name: file
                });
            }
        });
    }
  }

  public async upload() {
    const { ctx } = this;
    const stream = await ctx.getFileStream();
    // const filename = stream.filename;
    // const target = path.join(url, filename);

    // const writeStream = fs.createWriteStream(target);
    if(stream.mimeType == 'application/zip') {
        try {

            let dirPath = await temp.mkdir(folderName); // 临时文件夹

            // 解压上传文件的stream
            await this.doUnzipExtra(stream, dirPath);

            console.log('读取文件');
            let files:any = fs.readdirSync(dirPath);
            let msg = '', result = '';
            for(let file of files) {
                let flag = false;
                
                let arr = ['project.manifest', 'version.manifest', 'assets', 'src'];
                for(let fileName of arr) {
                    console.log(`${dirPath}/${file}/${fileName}`);
                    let result = fs.existsSync(`${dirPath}/${file}/${fileName}`);
                    if(!result) {
                        msg = '缺少文件' + fileName;
                        flag = true;
                        break;
                    }
                }
                if(flag) {
                    continue;
                } else {
                    result = file;
                    dirPath += `/${file}`;
                };
            }
            if(!result) {
                throw new Error(msg);
            }

            // 历史记录压缩移动
            console.log('历史记录压缩移动');
            let isEmpty = true;
            try {
                let oldFiles:any = fs.readdirSync(hotUpdateAddr);
                console.log(oldFiles.length);
                isEmpty = oldFiles.length <= 0;
            } catch(e) {
                isEmpty = true;
            }
            if(!isEmpty) {
                await compressing.zip.compressDir(hotUpdateAddr, `${dirPath}/${folderName}.zip`);
                if (!fs.existsSync(publishPath)) {
                    fs.mkdirSync(publishPath);
                }
                let versionManifest: string = '';
                try {
                    let version = JSON.parse(fs.readFileSync(`${hotUpdateAddr}/version.manifest`));
                    versionManifest = version.version;
                }catch(e) {
                    console.log(e);
                }
                fs.renameSync(`${dirPath}/${folderName}.zip`, `${publishPath}/${folderName}_${versionManifest}_${moment().format('YYMMDDHHmmss')}.zip`);
    
                // 删除原始文件
                this.deleteFolder(hotUpdateAddr);
            }
            
            // 保存新文件
            console.log('保存至热更新地址');
            fs.renameSync(dirPath, hotUpdateAddr);

            temp.cleanupSync();
            return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS);
            
        } catch (err) {
            console.log(err)
            return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR, null, err.message);
        }
        
    } else {
       return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR);
    }
  }

  private async doUnzipExtra(stream: Stream, dirPath: string) {
    return new Promise((resolve, reject) => {
        // 解压上传文件的stream
        var unzipExtractor = unzip.Extract({ path: dirPath });
        unzipExtractor.on('close', function() {
            resolve(null);
        });

        unzipExtractor.on('close', function(e) {
            reject(e);
        });

        stream.pipe(unzipExtractor); // 异步写入文件
    })
  }

  private jsonFolder = '/app/resource/jsons';
  private warjsonFolder = '/app/resource/warJsons';
  private tsFolder = '/app/pubUtils';

  private distJsonFolder = `/../game-server/dist${this.jsonFolder}`;
  private distWarjsonFolder = `/../game-server/dist${this.warjsonFolder}`;
  private distTsFolder = `/../game-server/dist${this.tsFolder}`;

  public async uploadJson() {
    const { ctx } = this;
    

    const parts = ctx.multipart({ });
    const files = [];

    try {
        let stream;
        let writeStream;

        while ((stream = await parts()) != null) {
            console.log('******', stream);
            const filename = stream.filename;
            let filenameWithoutEx = filename?filename.split('.')[0]:'';
            if (stream.mimeType == 'application/json') {
                if (filenameWithoutEx.match(/^\d{1,}$/)) {
                    let target1 = path.join(this.config.baseDir, this.warjsonFolder, filename);
                    let target2 = path.join(this.config.baseDir, this.distWarjsonFolder, filename);
                    writeStream = fs.createWriteStream(target1);
                    await pump(stream, writeStream);
                    fs.copyFileSync(target1, target2);
                    files.push(filename);
                } else {
                    let target1 = path.join(this.config.baseDir, this.jsonFolder, filename);
                    let target2 = path.join(this.config.baseDir, this.distJsonFolder, filename);
                    writeStream = fs.createWriteStream(target1);
                    await pump(stream, writeStream);
                    fs.copyFileSync(target1, target2);
                    files.push(filename);
                }
            } else if (stream.mimeType == 'application/octet-stream') {
                let target1 = path.join(this.config.baseDir, this.tsFolder, 'dicParam.js');
                let target2 = path.join(this.config.baseDir, this.distTsFolder, filename);
                writeStream = fs.createWriteStream(target1);
                await pump(stream, writeStream);
                fs.copyFileSync(target1, target2);
                files.push(filename);
            }

            let envs = decodeArrayStr(ctx.request.headers.env||'', ',');

            if(envs.length > 0) { // 转发
                for(let env of envs) {
                    if(env == ctx.app.config.realEnv) continue;
                    await ctx.service.utils.transmit(env, ctx.request.url, writeStream);
                }
            }
            sendToWormhole(stream);
        }

    }catch(e) {
        console.error(e);
    }

    return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, {
        "files": files
    });

    // console.log('****', stream);
    // // const filename = stream.filename;
    // // const target = path.join(url, filename);

    // if(stream.mimeType == 'application/zip') {
    //     try {
    //         let dirPath = await temp.mkdir(this.jsonFolderName); // 临时文件夹

    //         console.log('读取文件');
    //         await this.doUnzipExtra(stream, dirPath);
    //         let files = new Array<{path:string,name:string}>();
    //         this.getFileList(dirPath, files);
    //         console.log(files);

    //         console.log('保存文件');
    //         if (!fs.existsSync(this.jsonFolderPath)) {
    //             fs.mkdirSync(this.jsonFolderPath);
    //         }
    //         for (let {path, name} of files) {
    //             console.log(`${this.jsonFolderPath}/${name}`);
    //             fs.renameSync(path, `${this.jsonFolderPath}/${name}`);
    //         }

    //         temp.cleanupSync();
    //         return ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, {
    //             "files": JSON.stringify(files)
    //         });
    //     } catch (err) {
    //         console.log(err)
    //         return ctx.body = ctx.service.utils.resResult(STATUS.INTERNAL_ERR);
    //     }
        
    // } else {
    //     return ctx.body = ctx.service.utils.resResult(STATUS.GM_UPLOAD_FORMAT_ERR);
    // }
  }

  public async reloadResource() {
    const { ctx } = this;

    try {
        
        reloadResources();
        ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: true });
        return;
    } catch(e) {
        ctx.body = ctx.service.utils.resResult(STATUS.SUCCESS, { isOK: false, err: e.stack });
        return;
    }
}
}

export function childExec(commond: string) {
    return new Promise((resolve, reject) => {
        exec(commond, function(error, stdout, stderr){
            if(error) {
                reject(error);
                return;
            }
            console.log('stdout: ' + stdout);
            console.log('stderr: ' + typeof stderr);
            resolve(stdout);
        });
    })
}