import sublime
from sublime_plugin import TextCommand

from GitSavvy.common import util
from ...core.git_command import GitCommand
from ..github import open_file_in_browser  # , open_repo, open_issues
from ..github import open_repo
from ..github import open_issues

from .. import git_mixins
from ...core.ui_mixins.quick_panel import show_remote_panel


EARLIER_COMMIT_PROMPT = ("The remote chosen may not contain the commit. "
                         "Open the file {} before?")


class GsGithubOpenFileOnRemoteCommand(TextCommand, GitCommand, git_mixins.GithubRemotesMixin):

    """
    Open a new browser window to the web-version of the currently opened
    (or specified) file. If `preselect` is `True`, include the selected
    lines in the request. If the active tracked remote is the same as the
    integrated remote, open browser directly, if not, display a list to remotes
    to choose from.

    At present, this only supports github.com and GitHub enterprise.
    """

    def run(self, edit, remote=None, preselect=False, fpath=None):
        sublime.set_timeout_async(
            lambda: self.run_async(remote, preselect, fpath))

    def run_async(self, remote, preselect, fpath):
        self.fpath = fpath or self.get_rel_path()
        self.preselect = preselect

        self.remotes = self.get_remotes()

        if not remote:
            remote = self.guess_github_remote()

        if remote:
            self.open_file_on_remote(remote)
        else:
            show_remote_panel(self.open_file_on_remote)

    def open_file_on_remote(self, remote):
        if not remote:
            return

        fpath = self.fpath
        if isinstance(fpath, str):
            fpath = [fpath]
        remote_url = self.remotes[remote]

        if self.view.settings().get("git_savvy.show_file_at_commit_view"):
            # if it is a show_file_at_commit_view, get the hash from settings
            commit_hash = self.view.settings().get("git_savvy.show_file_at_commit_view.commit")
        else:
            commit_hash = self.get_commit_hash_for_head()

        base_hash = commit_hash

        # check if the remote contains the commit hash
        if remote not in self.remotes_containing_commit(commit_hash):
            upstream = self.get_upstream_for_active_branch()
            if upstream:
                merge_base = self.git("merge-base", commit_hash, upstream).strip()
                if merge_base and remote in self.remotes_containing_commit(merge_base):
                    count = self.git(
                        "rev-list", "--count", "{}..{}".format(merge_base, commit_hash)).strip()
                    if not sublime.ok_cancel_dialog(EARLIER_COMMIT_PROMPT.format(
                            count + (" commit" if count == "1" else " commits"))):
                        return

                    commit_hash = merge_base
            else:
                util.view.flash(self.view, "This revision has not been pushed upstream yet.")
                return

        start_line = None
        end_line = None

        if self.preselect and len(fpath) == 1:
            selections = self.view.sel()
            if len(selections) >= 1:
                first_selection = selections[0]
                last_selection = selections[-1]
                # Git lines are 1-indexed; Sublime rows are 0-indexed.
                start_line = self.view.rowcol(first_selection.begin())[0] + 1
                end_line = self.view.rowcol(last_selection.end())[0] + 1

                # forward line number if the opening commit is the merge base
                if base_hash != commit_hash:
                    diff = self.no_context_diff(base_hash, commit_hash, fpath[0])
                    start_line = self.adjust_line_according_to_diff(diff, start_line)
                    end_line = self.adjust_line_according_to_diff(diff, end_line)

        for p in fpath:
            open_file_in_browser(
                p,
                remote_url,
                commit_hash,
                start_line=start_line,
                end_line=end_line
            )


class GsGithubOpenRepoCommand(TextCommand, GitCommand, git_mixins.GithubRemotesMixin):

    """
    Open a new browser window to the GitHub remote repository.
    """

    def run(self, edit, remote=None):
        sublime.set_timeout_async(lambda: self.run_async(remote))

    def run_async(self, remote):
        self.remotes = self.get_remotes()

        if not remote:
            remote = self.guess_github_remote()

        if remote:
            open_repo(self.remotes[remote])
        else:
            show_remote_panel(self.on_remote_selection)

    def on_remote_selection(self, remote):
        if not remote:
            return
        open_repo(self.remotes[remote])


class GsGithubOpenIssuesCommand(TextCommand, GitCommand, git_mixins.GithubRemotesMixin):

    """
    Open a new browser window to the GitHub remote repository's issues page.
    """

    def run(self, edit):
        open_issues(self.get_integrated_remote_url())