"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
//import { GitCreateBlobResponse, GitCreateTreeParamsTree } from '@octokit/git';
const rest_1 = require("@octokit/rest");
const ste_events_1 = require("ste-events");
const IFileDifference_1 = require("../storage/IFileDifference");
const Utilities_1 = require("../core/Utilities");
const Constants_1 = require("../core/Constants");
class GitHubManager {
    static githubAuthenticationCompleted(newToken) {
        GitHubManager._tokenFromLogin = newToken;
        GitHubManager._onAuthenticated.dispatch("", "");
    }
    static get isSignedIn() {
        return ((this._tokenFromLogin !== undefined && this._tokenFromLogin !== "") ||
            (this._tokenFromPrefs !== undefined && this._tokenFromPrefs !== ""));
    }
    static signIn() {
        // @ts-ignore
        if (typeof window !== "undefined") {
            // @ts-ignore
            const result = window.prompt("This is really really preview. You should not use any work or meaningful GitHub accounts with this - yet. Type yes to go ahead anyways.");
            if (result !== "yes") {
                return;
            }
            // @ts-ignore
            window.open("/Auth/Login", "login", "width=600,height=700,resizable=off");
        }
    }
    static get onAuthenticated() {
        return GitHubManager._onAuthenticated.asEvent();
    }
    static init() {
        // @ts-ignore
        if (typeof window !== "undefined") {
            // @ts-ignore
            window.githubAuthenticationCompleted = GitHubManager.githubAuthenticationCompleted;
        }
    }
    get repos() {
        if (this._reposResponse === undefined) {
            return undefined;
        }
        return this._reposResponse.data;
    }
    get authenticatedUser() {
        if (this._userResponse === undefined) {
            return undefined;
        }
        return this._userResponse.data;
    }
    get octokit() {
        return this._octokit;
    }
    constructor(prefsStorageFile) {
        this._isUserStateLoaded = false;
        this._onAuthenticated = this._onAuthenticated.bind(this);
        this._octokit = new rest_1.Octokit({
            auth: "",
            userAgent: Constants_1.constants.name + " " + Constants_1.constants.version,
        });
        this._prefsFile = prefsStorageFile;
        // GitHubManager.onAuthenticated.subscribe(this._onAuthenticated);
    }
    _onAuthenticated(dummy, dummy2) {
        this._savePrefs();
    }
    async _loadPrefs() {
        if (this._prefsFile === undefined) {
            return;
        }
        await this._prefsFile.loadContent();
        if (this._prefsFile.content !== undefined && typeof this._prefsFile.content === "string") {
            this._data = JSON.parse(this._prefsFile.content);
        }
        if ((this._data === undefined || this._data.authToken === undefined) &&
            GitHubManager._tokenFromLogin !== undefined) {
            this._savePrefs();
        }
        else if (this._data !== undefined && this._data.authToken !== undefined) {
            if (GitHubManager._tokenFromPrefs === undefined) {
                GitHubManager._tokenFromPrefs = this._data.authToken;
            }
            this._octokit = new rest_1.Octokit({
                // auth: this._data.authToken,
                userAgent: Constants_1.constants.name + " " + Constants_1.constants.version,
            });
        }
    }
    async _savePrefs() {
        if (this._prefsFile === undefined) {
            return;
        }
        if (this._data === undefined) {
            this._data = {};
        }
        if (GitHubManager._tokenFromLogin !== undefined) {
            this._data.authToken = GitHubManager._tokenFromLogin;
        }
        if (this.authenticatedUser !== undefined && this.authenticatedUser.name !== null) {
            this._data.userName = this.authenticatedUser.name;
        }
        this._prefsFile.setContent(JSON.stringify(this._data));
        await this._prefsFile.saveContent();
    }
    async ensureUserStateLoaded() {
        if (this._isUserStateLoaded) {
            return;
        }
        await this._loadPrefs();
        const userResponse = await this._octokit.rest.users.getAuthenticated();
        this._userResponse = userResponse;
        const response = await this._octokit.rest.repos.listForAuthenticatedUser();
        this._reposResponse = response;
        this._isUserStateLoaded = true;
    }
    async createRepo(name, description) {
        const result = await this._octokit.repos.createForAuthenticatedUser({
            name: name,
            description: description,
            auto_init: true,
        });
        return result.data;
    }
    async commitToRepo(owner, repo, branch = "main", folderName = "", commitMessage, differences) {
        // gets commit's AND its tree's SHA
        const currentCommit = await this.getCurrentCommit(owner, repo, branch);
        const filesBlobs = [];
        const pathsForBlobs = [];
        for (let i = 0; i < differences.fileDifferences.length; i++) {
            const diff = differences.fileDifferences[i];
            if ((diff.type === IFileDifference_1.FileDifferenceType.contentsDifferent || diff.type === IFileDifference_1.FileDifferenceType.fileAdded) &&
                diff.updated !== undefined) {
                const updatedFile = diff.updated;
                await updatedFile.loadContent();
                if (updatedFile.content !== null) {
                    let targetPath = diff.path;
                    targetPath = folderName + targetPath;
                    if (targetPath.startsWith("/")) {
                        targetPath = targetPath.substring(1, targetPath.length);
                    }
                    const file = await this.createBlobForFile(owner, repo, updatedFile.content);
                    filesBlobs.push(file);
                    pathsForBlobs.push(targetPath);
                }
            }
        }
        const newTree = await this.createNewTree(owner, repo, filesBlobs, pathsForBlobs, currentCommit.treeSha);
        const newCommit = await this.createNewCommit(owner, repo, commitMessage, newTree.sha, currentCommit.commitSha);
        this.setBranchToCommit(owner, repo, branch, newCommit.sha);
    }
    async createBlobForFile(owner, repo, content) {
        let encoding = "utf-8";
        if (content instanceof Uint8Array) {
            content = Utilities_1.default.uint8ArrayToBase64(content);
            encoding = "base64";
        }
        const blobData = await this._octokit.git.createBlob({
            owner: owner,
            repo,
            content,
            encoding: encoding,
        });
        return blobData.data;
    }
    async getCurrentCommit(owner, repo, branch = "main") {
        const { data: refData } = await this._octokit.git.getRef({
            owner: owner,
            repo,
            ref: "heads/" + branch,
        });
        const commitSha = refData.object.sha;
        const { data: commitData } = await this._octokit.git.getCommit({
            owner: owner,
            repo,
            commit_sha: commitSha,
        });
        return {
            commitSha,
            treeSha: commitData.tree.sha,
        };
    }
    async createNewTree(owner, repo, blobs, paths, parentTreeSha) {
        // My custom config. Could be taken as parameters
        const tree = blobs.map(({ sha }, index) => ({
            path: paths[index],
            mode: `100644`,
            type: `blob`,
            sha,
        }));
        const { data } = await this._octokit.git.createTree({
            owner,
            repo,
            tree,
            base_tree: parentTreeSha,
        });
        return data;
    }
    async createNewCommit(owner, repo, message, currentTreeSha, currentCommitSha) {
        const result = await this._octokit.git.createCommit({
            owner: owner,
            repo,
            message,
            tree: currentTreeSha,
            parents: [currentCommitSha],
        });
        return result.data;
    }
    setBranchToCommit(owner, repo, branch = `main`, commitSha) {
        this._octokit.git.updateRef({
            owner: owner,
            repo,
            ref: `heads/${branch}`,
            sha: commitSha,
        });
    }
}
exports.default = GitHubManager;
GitHubManager._tokenFromLogin = "";
GitHubManager._tokenFromPrefs = "";
GitHubManager._onAuthenticated = new ste_events_1.EventDispatcher();

//# sourceMappingURL=../maps/github/GitHubManager.js.map
