import simpleGit, { SimpleGit, SimpleGitOptions } from 'simple-git';
import { PROJECT_SRC_PATH } from './config';
import UserConfig from './userConfig';

const util = require('util');
const exec = util.promisify(require('child_process').exec);

const DEFAULT_REMOTE = 'origin';
const DEFAULT_BRANCH = 'master';

export default class GitMission {

    private git: SimpleGit;

    constructor(private userConfig: UserConfig) {
        const options: Partial<SimpleGitOptions> = {
            baseDir: PROJECT_SRC_PATH,
            binary: 'git',
            maxConcurrentProcesses: 2,
        };

        this.git = simpleGit(options);
    }

    async setupSshAgent() {
        const { err, stderr, stdout } = await exec(`eval "$(ssh-agent -s)" && ssh-keyscan -p ${this.userConfig.getGiteaSshPort()} -H ${this.userConfig.getGiteaHost()} >> ~/.ssh/known_hosts`);

        console.log(stdout);

        if (err) {
            console.error(stderr);
            throw new Error(err);
        }

    }

    get author() {

        return this.userConfig.getUsername();
    }

    async init() {
        try {

            console.log('Setup ssh agent');
            await this.setupSshAgent();

            console.log('Init Git mission..');

            const remote = await this.readRemote();
            if (remote === DEFAULT_REMOTE) {
                return Promise.resolve(this);
            }

            const remotePath = this.getRemotePath();

            await this.git.init();
            await this.git.addRemote(DEFAULT_REMOTE, remotePath);
            await this.git.addConfig('user.email', this.userConfig.getCurrentUserDetails().email, false, "system");
            await this.git.addConfig('user.name', `${this.userConfig.getCurrentUserDetails().lastName} ${this.userConfig.getCurrentUserDetails().firstName}`, false, "system");

            return Promise.resolve(this);
        } catch (e) {
            console.error(e);
            return Promise.reject(e);
        }
    }

    private getRemotePath() {
        return `ssh://git@${this.userConfig.getGiteaHost()}:${this.userConfig.getGiteaSshPort()}/${this.userConfig.getRemoteGitUsername()}/${this.userConfig.getMissionId()}`;
    }

    async readRemote() {
        try {
            return (await this.git.remote([]) || '').replace(/(\r\n|\n|\r)/gm, '');
        } catch (e) {
            // ignore it, maybe the git repo does not exist
        }
        return '';
    }

    fetch() {
        return this.git.fetch(DEFAULT_REMOTE);
    }

    pull() {
        return this.git.pull(DEFAULT_REMOTE, DEFAULT_BRANCH, { '--rebase': 'true' });
    }

    addAll() {
        return this.git.add('.');
    }

    commit(message) {
        return this.git.commit(message);
    }

    push() {
        return this.git.push(DEFAULT_REMOTE, DEFAULT_BRANCH);
    }

    async isRemoteRepoExist() {
        try {
            const remotes = await this.git.listRemote();
            return remotes.length !== 0;
        } catch {
            // error, Gitea throws Gitea: Unauthorized when not found
            return false;
        }
    }
}