import { Singleton, Container, Scope, Inject } from "typescript-ioc";
import { ShellUtils, ShellOut } from './ShellUtils'
import { OpResult } from 'mslib'
import { DaoUtils } from './DaoUtils'
import { FileUtils } from './FileUtils'


export class GitUtils {


    /**
     * GIT 项目clone
     * @param dir 本地磁盘目录
     * @param gitUrl GIT仓库地址
     * @param username GIT用户名
     * @param password GIT密码
     * @param projectAlias 项目别名
     * 
     */
    static async clone(dir: string, gitUrl: string, username: string, password: string, projectAlias: string = ''): Promise<OpResult<any>> {
        await FileUtils.mkdir(dir);
        let projectDir = ''
        if (!DaoUtils.isEmpty(projectAlias)) {
            projectDir = dir + '/' + projectAlias
        } else {
            projectDir = dir + '/' + (gitUrl.substring(gitUrl.lastIndexOf('/') + 1, gitUrl.length).replace('.git', ''))
        }
        const isExists = await FileUtils.exists(projectDir);
        if (isExists) {
            return OpResult.success('OK')
        }
        const url = gitUrl.replace('://', `://${encodeURIComponent(username)}:${encodeURIComponent(password)}@`)
        const cmd = `cd ${dir}; git clone ${url} ${projectAlias}`;
        return await ShellUtils.exec(cmd)
    }


    /**
     * 通过Git指令获取指定项目的git版本分支列表
     * @param projectDir 项目目录地址
     */
    static async getBranchs(projectDir: string): Promise<OpResult<Array<string>>> {
        const isExists = await FileUtils.exists(projectDir);
        if (!isExists) {
            return OpResult.error(`获取失败，项目不存在[${projectDir}]`)
        }
        const cmd = `cd ${projectDir};git remote update origin --prune;git branch -a`
        const op = await ShellUtils.exec(cmd)
        if (!op.isSuccess()) {
            return OpResult.error(op.message)
        }
        const msg = op.data
        if (DaoUtils.isEmpty(msg)) {
            return OpResult.error(`获取Branch失败 ${msg.stderr}`)
        }
        const branches = msg.stdout
        const reg = new RegExp('remotes/origin/', 'g');


        const result = [];
        const remotes = branches
            .substring(branches.indexOf('remotes'))
            .replace(reg, '')
            .split('\n');


        for (let branche of remotes) {
            branche = branche.trim();
            if (branche === '' || !branche.includes('.')) {
                continue;
            }
            if (branche.indexOf('/') != -1) {
                result.push(branche.substr(branche.indexOf('/') + 1));
            } else {
                result.push(branche);
            }
        }

        return OpResult.success('OK', result.sort(this.sort).reverse())
    }

    /**
     * 拉取指的分支代码
     * @param projectDir 项目目录
     * @param branch    分支
     */
    static async pull(projectDir: string, branch: string): Promise<OpResult<any>> {
        const isExists = await FileUtils.exists(projectDir);
        if (!isExists) {
            return OpResult.error(`获取失败，项目不存在[${projectDir}]`)
        }
        let cmd = `cd ${projectDir};git remote update origin --prune;git reset --hard;git checkout ${branch};git pull;`
        let op = await ShellUtils.exec(cmd)
        if (!op.isSuccess()) {
            return op
        }
        if (DaoUtils.isEmpty(op.data.stderr)) {
            return op
        }
        const stderr = op.data.stderr.toLowerCase();
        if (stderr.indexOf('switched') === -1 && stderr.indexOf('already') === -1) {
            return OpResult.error(op.data.stderr, op.data)
        }
        return op
    }

    private static sort(v1: string, v2: string) {
        let items1 = v1.split('.');
        let items2 = v2.split('.');
        let len = Math.max(items1.length, items2.length);
        let k = 0;
        for (let i = 0; i < len; i++) {
            let a1 = items1[i];
            let b1 = items2[i];
            if (typeof a1 === 'undefined') {
                k = -1;
                break;
            } else if (typeof b1 === 'undefined') {
                k = 1;
                break;
            } else {
                if (a1 === b1) {
                    continue;
                }
                k = Number(a1) - Number(b1);
                break;
            }
        }
        return k;
    }
}