import * as path from "path";
import * as fs from "fs";
import ProgressBar from "progress";
import OSS from "ali-oss";

interface IAutoUploadOptions {
  dir: string,
  originDir: string,
  bucket: string,
  accessKeyId: string,
  accessKeySecret: string,
  region: string,
}

export default class AutoUpload {
  options: IAutoUploadOptions = {
    dir: "",
    originDir: "",
    region: "oss-cn-hangzhou",
    accessKeyId: "",
    accessKeySecret: "",
    bucket: ""
  };

  client = null;
  bar = null;
  private _files: any[];
  private existFiles: number = 0;
  private uploadFiles: number = 0;
  private errorFiles: number = 0;

  constructor(props: IAutoUploadOptions) {

    this.options = Object.assign({}, this.options, props);

    const checkOptions = [
      "dir", "originDir",
      "bucket", "region",
      "accessKeySecret", "accessKeyId",
    ];

    for (const optionKey of checkOptions) {
      if (!this.options[optionKey]) {
        throw new Error(`AutoUpload: required option "${optionKey}"`);
      }
    }

    this.init();
  }

  init() {
    const {accessKeyId, accessKeySecret, bucket, region} = this.options;
    this.client = new OSS({region, accessKeyId, accessKeySecret, bucket});

    this.bar = new ProgressBar(`文件上传中 [:bar] :current/${this.files().length} :percent :elapseds`, {
      complete: "●",
      incomplete: "○",
      width: 20,
      total: this.files().length,
      callback: () => {
        console.log("%cAll complete.", "color: green");
        console.log(`%c本次队列文件共${this.files().length}个，已存在文件${this.existFiles}个，上传文件${this.uploadFiles}个，上传失败文件${this.errorFiles}个`, "color: green");
      }
    })
    return this;
  }

  files() {
    if (this._files) return this._files;
    this._files = [];

    /**
     * 文件遍历方法
     * @param filePath 需要遍历的文件路径
     */
    const fileDisplay = (filePath) => {
      //根据文件路径读取文件，返回文件列表
      const files = fs.readdirSync(filePath);

      files.forEach((filename) => {
        //获取当前文件的绝对路径
        const fileDir = path.join(filePath, filename);
        //根据文件路径获取文件信息，返回一个fs.Stats对象
        const stats = fs.statSync(fileDir);
        const isFile = stats.isFile();//是文件
        const isDir = stats.isDirectory();//是文件夹
        if (isFile) {
          this._files.push(fileDir);
        } else if (isDir) {
          fileDisplay(fileDir);//递归，如果是文件夹，就继续遍历该文件夹下面的文件
        }
      });
    }

    //调用文件遍历方法
    fileDisplay(this.options.dir);
    return this._files;
  }

  async start() {
    const ps = this.files().map((file) => {

      const relativePath = path.relative(this.options.dir, file)
        .replace(path.sep, "/");

      this.existFiles = 0;
      this.uploadFiles = 0;
      this.errorFiles = 0;

      const originPath = `${this.options.originDir}${relativePath}`;

      return (async () => {
        let originFile = null;

        originFile = await this.client.head(originPath)
          .catch((error: Error) => originFile = error);

        try {
          if (originFile.status === 404) {
            await this.client.put(originPath, file);
            this.uploadFiles += 1;
          } else {
            this.existFiles += 1;
          }
        } catch (error) {
          this.errorFiles += 1;
        }
        this.bar.tick();
      })();
    });

    await Promise.all(ps).catch((err) => {
      console.error("上传错误", err);
    });

  }
}
