import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs-extra';
import path from 'path';
import { getPackageInfo, TPackageVersion } from './package';

export interface IVersion {
  /**
   * 是否新增一个版本号
   */
  isAdd: () => boolean;
  /**
   * 是否需要更新对应的版本号
   */
  isUpdate: () => boolean;

  /**
   * 回退到之前的配置文件
   * @remarks
   * 先更新配置文件 然后再进行编译
   * 有可能编译失败 因此这个时候需要进行回退
   */
  rollback: () => void;

  /**
   * 获取上一个版本号
   * @remarks
   * 在推送时 需要清空上一个版本号的文件
   */
  getLastVersion: () => string;

  /**
   * 对比版本号
   */
  patch: () => void;
}

export class VersionManage implements IVersion {
  private readonly BaseHref = '/';
  private __configBak: string | null = null;
  private readonly versionConfigPath = path.resolve(__dirname, '../config/version.json');
  private readonly packagePath = path.resolve(__dirname, '../package.json');
  // 是否新建版本的差值
  private readonly versionDifference = -100;
  // 存储差值
  private difference: number | null = null;
  private getVersionPath(version: TPackageVersion): string {
    return `${this.BaseHref}${version}/`;
  }

  /**
   * 版本号的比较函数
   */
  private versionCompareFn(a: TPackageVersion, b: TPackageVersion): number {
    const [majorA, minorA, patchA] = a.split('.').map(str => parseInt(str, 10));
    const [majorB, minorB, patchB] = b.split('.').map(str => parseInt(str, 10));
    if (majorA > majorB) {
      return -100;
    }
    if (minorA > minorB) {
      return -10;
    }
    if (patchA > patchB) {
      return -1;
    }
    return 1;
  }

  patch() {
    const currentVersion = this.getPackageVersion();
    const versionMap = this.getVersionMap();
    const latestVersion = (Object.keys(versionMap).filter(key => key !== 'master') as TPackageVersion[]).sort(
      this.versionCompareFn
    )[0];
    const branchName = this.getCurrentBranch();
    if (branchName === 'master') {
      return this.updateVersion(versionMap, currentVersion, latestVersion);
    }
    if (!branchName.startsWith('release')) {
      throw new Error(`当前分支 [${branchName}] 不允许发布版本`);
    }
    /**
     * 如果当前分支为release-X
     * 那么存在latestVersion为 null 的情况
     * 那么直接判断为新增版本
     */
    const value = latestVersion ? this.versionCompareFn(currentVersion, latestVersion) : this.versionDifference;
    this.bakVersion();
    if (value === this.versionDifference) {
      this.addVersion(versionMap, currentVersion);
    } else if (value < 0) {
      this.updateVersion(versionMap, currentVersion, latestVersion);
    } else if (currentVersion !== latestVersion) {
      throw Error(`当前版本号( ${currentVersion} ) 不能小于上次发布的版本号( ${latestVersion} )`);
    }
  }

  /**
   * 还原备份
   */
  rollback(): void {
    if (this.__configBak) {
      writeFileSync(this.versionConfigPath, this.__configBak);
    }
    this.__configBak = null;
  }

  addVersion(map: IVersionConfig, version: TPackageVersion): void {
    console.log('添加新版本文档版本号: ', version);
    const _versionMap = {
      ...map,
      [version]: this.getVersionPath(version),
    };
    writeFileSync(this.versionConfigPath, JSON.stringify(_versionMap, null, 2));
  }

  getLastVersion(): string {
    const branch = this.getCurrentBranch();
    if (branch === 'master') {
      return 'master';
    }
    const versionList = this.getVersionMapByBak();
    if (!branch.startsWith('release'))
      throw new Error(`当前分支名 [${branch}] 不符合发布标准 ['master'、'release-X'] `);
    const majorVersion = branch.match(/\d+/)![0];
    const lastVersion = Object.keys(versionList).find(version => {
      const major = version.split('.')[0];
      return major === majorVersion;
    });
    if (lastVersion) return lastVersion;
    if (this.isAdd()) {
      throw new Error('无法获取到上个版本的版本号');
    }
    return '__'; // 新增的情况下 返回个不存在的文件
  }

  updateVersion(map: IVersionConfig, version: TPackageVersion, overwriteVersion: TPackageVersion): void {
    const branch = this.getCurrentBranch();
    let _versionMap = {
      ...map,
    };
    if (branch === 'master') {
      console.log(`更新master版本号`);
      const key = branch as any;
      _versionMap[key] = this.getVersionPath('master' as any);
    } else {
      console.log(`更新文档版本号: ${overwriteVersion} -> ${version}`);

      _versionMap[version] = this.getVersionPath(version);
      _versionMap[overwriteVersion] = undefined as unknown as any;
    }

    writeFileSync(this.versionConfigPath, JSON.stringify(_versionMap, null, 2));
  }

  getVersionMap(): IVersionConfig {
    const str = readFileSync(this.versionConfigPath, 'utf8');
    return JSON.parse(str);
  }

  getPackageVersion(): TPackageVersion {
    const packageInfo = getPackageInfo(this.packagePath);
    return packageInfo.version;
  }

  isAdd(): boolean {
    return this.getDifference() === this.versionDifference;
  }

  isUpdate(): boolean {
    const value = this.getDifference();
    return value > 0 && value < this.versionDifference;
  }

  /**
   * 获取备份的版本列表
   * @remarks
   * 当我们编译之后 如果再通过读取文件时无法获取到上一个最新版本
   * 因此 通过读取被封的文件信息
   */
  private getVersionMapByBak(): IVersionConfig {
    if (this.__configBak) return JSON.parse(this.__configBak);
    throw new Error('备份信息为空');
  }

  /**
   * 存在内存里
   */
  private bakVersion(): void {
    this.__configBak = readFileSync(this.versionConfigPath, 'utf-8');
  }

  private getCurrentBranch() {
    /**
     * jenkins里的环境变量
     * GIT_BRANCH -> origin/XXXX
     * 不需要前面的origin
     * 如果没有 直接跑git
     */
    const jenkinsBranch = process.env.GIT_BRANCH?.split('/').pop();
    return jenkinsBranch || execSync('git rev-parse --abbrev-ref  HEAD').toString().trim();
  }

  private getDifference(): number {
    if (this.difference === null) {
      const currentVersion = getPackageInfo(this.packagePath).version;
      const versionMap = this.getVersionMap();
      const latestVersion = (Object.keys(versionMap) as TPackageVersion[]).sort(this.versionCompareFn)[0];
      const value = this.versionCompareFn(currentVersion, latestVersion);
      this.difference = value;
    }
    return this.difference;
  }
}

export interface IVersionConfig {
  [version: TPackageVersion]: string;
}
