import os
import subprocess
import shutil
import tempfile
from git import Repo, GitCommandError

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
GIT_EXTRAS_BIN = os.path.abspath(os.path.join(CURRENT_DIR, "..", "bin"))
GIT_EXTRAS_HELPER = os.path.abspath(os.path.join(CURRENT_DIR, "..", "helper"))

GITHUB_ORIGIN = "https://github.com/tj/git-extras.git"
GITLAB_ORIGIN = "https://gitlab.com/tj/git-extras.git"
BITBUCKET_ORIGIN = "https://bitbucket.org/tj/git-extras.git"


class TempRepository:
    def __init__(self, repo_work_dir=None):
        self._system_tmpdir = tempfile.gettempdir()
        if repo_work_dir is None:
            repo_work_dir = tempfile.mkdtemp()
        else:
            repo_work_dir = os.path.join(self._system_tmpdir, repo_work_dir)
        self._cwd = repo_work_dir
        self._tempdirname = self._cwd[len(self._system_tmpdir) + 1 :]
        self._git_repo = Repo.init(repo_work_dir, b="default")
        self._files = []
        self.change_origin_to_github()

    def switch_cwd_under_repo(self):
        os.chdir(self._cwd)
        print(f"The current work directory has switched to {self._cwd}")

    def get_cwd(self):
        return self._cwd

    def get_repo_dirname(self):
        return self._tempdirname

    def get_repo_git(self):
        return self._git_repo.git

    def get_file(self, index):
        return self._files[index]

    def get_filename(self, index):
        file = self._files[index]
        return file[1:]

    def get_files(self):
        return self._files

    def create_tmp_dir(self):
        tmp_dir = tempfile.mkdtemp()
        return tmp_dir

    def create_tmp_file(self, temp_dir=None):
        if temp_dir is None:
            temp_dir = self._cwd

        tmp_file = tempfile.mkstemp(dir=temp_dir)
        self._files.append(tmp_file[1])
        return tmp_file

    def remove_tmp_file(self, file_path):
        os.remove(file_path)
        print(f"File {file_path} has been removed")

    def writefile(self, temp_file, data):
        if data is None:
            return

        with open(temp_file, "w", encoding="utf-8") as f:
            f.write(data)

    def teardown(self):
        shutil.rmtree(self._cwd, ignore_errors=True)
        print(f"The temp directory {self._cwd} has been removed")

    def invoke_extras_command(self, name, *params):
        command_name = "git-" + name
        print(f"Invoke the git-extras command - {command_name} at {self._cwd}")
        script = [os.path.join(GIT_EXTRAS_BIN, command_name), *list(params)]
        print(f"Run the script \"{' '.join(script)}\"")
        return subprocess.run(script, capture_output=True)

    def invoke_installed_extras_command(self, name, *params):
        command_name = "git-" + name
        print(f"Invoke the git-extras command - {command_name} at {self._cwd}")
        origin_extras_command = os.path.join(GIT_EXTRAS_BIN, command_name)
        temp_extras_command = os.path.join(self._cwd, command_name)
        helpers = [
            os.path.join(GIT_EXTRAS_HELPER, "git-extra-utility"),
            os.path.join(GIT_EXTRAS_HELPER, "is-git-repo"),
        ]

        if not os.path.exists(temp_extras_command):
            whole = []
            with open(temp_extras_command, "w") as t:
                for helper in helpers:
                    with open(helper) as h:
                        content = h.read()
                        whole.extend(content.splitlines())
                with open(origin_extras_command) as o:
                    content = o.read()
                    first, *rest = content.splitlines()
                    whole.extend(rest)
                    whole.insert(0, first)
                t.write("\n".join(whole))
                print(f"Update file {temp_extras_command}")
            os.chmod(temp_extras_command, 0o775)

        script = [temp_extras_command, *params]
        print(f'Run the script "{script}"')
        return subprocess.run(script, capture_output=True)

    def change_origin(self, origin_url):
        try:
            self._git_repo.git.remote("add", "origin", origin_url)
        except GitCommandError as err:
            print(err)
        self._git_repo.git.remote("set-url", "origin", origin_url)

    def change_origin_to_github(self):
        self.change_origin(GITHUB_ORIGIN)

    def change_origin_to_gitlab(self):
        self.change_origin(GITLAB_ORIGIN)

    def change_origin_to_bitbucket(self):
        self.change_origin(BITBUCKET_ORIGIN)
