"""Utilities for interacting with GitHub"""
import os
import json
import webbrowser
import stat
import sys
from git import Repo

from .context import Context

event_dict = {
    "added_to_project": (
        lambda event: "{} added the issue to a project.".format(event["actor"]["login"])
    ),
    "assigned": (
        lambda event: "{} assigned the issue to {}.".format(
            event["actor"]["login"], event["assignee"]["login"]
        )
    ),
    "closed": (lambda event: "{} closed this issue.".format(event["actor"]["login"])),
    "converted_note_to_issue": (
        lambda event: "{} created this issue from a note.".format(
            event["actor"]["login"]
        )
    ),
    "demilestoned": (lambda event: "The issue was removed from a milestone."),
    "head_ref_deleted": (lambda event: "The pull request's branch was deleted."),
    "head_ref_restored": (lambda event: "The pull request's branch was restored."),
    "labelled": (
        lambda event: "{} added {} label to the issue.".format(
            event["actor"]["login"], event["label"]
        )
    ),
    "locked": (
        lambda event: "The issue was locked by {}.".format(event["actor"]["login"])
    ),
    "mentioned": (
        lambda event: "{} was mentioned in the issue's body.".format(
            event["actor"]["login"]
        )
    ),
    "marked_as_duplicate": (
        lambda event: "The issue was marked duplicate by {}.".format(
            event["actor"]["login"]
        )
    ),
    "merged": (
        lambda event: "The issue was merged by {}.".format(event["actor"]["login"])
    ),
    "milestoned": (lambda event: "The issue was added to a milestone."),
    "moved_columns_in_project": (
        lambda event: "The issue was moved between columns in a project board."
    ),
    "referenced": (lambda event: "The issue was referenced from a commit message."),
    "renamed": (lambda event: "The title of the issue was changed."),
    "reopened": (
        lambda event: "The issue was reopened by {}".format(event["actor"]["login"])
    ),
    "review_dismissed": (
        lambda event: "{} dismissed a review from the pull request.".format(
            event["actor"]["login"]
        )
    ),
    "review_requested": (
        lambda event: "{} requested review from the subject on this pull request.".format(
            event["actor"]["login"]
        )
    ),
    "review_request_removed": (
        lambda event: "{} removed the review request for the subject on this pull request.".format(
            event["actor"]["login"]
        )
    ),
    "subscribed": (
        lambda event: "{} subscribed to receive notifications for the issue.".format(
            event["actor"]["login"]
        )
    ),
    "transferred": (lambda event: "The issue was transferred to another repository."),
    "unassigned": (
        lambda event: "{} was unassigned from the issue.".format(
            event["actor"]["login"]
        )
    ),
    "unlabeled": (lambda event: "A label was removed from the issue."),
    "unlocked": (
        lambda event: "The issue was unlocked by {}".format(event["actor"]["login"])
    ),
    "unmarked_as_duplicate": (lambda event: "The was unmarked as dublicate."),
    "user_blocked": (lambda event: "A user was blocked from the organization."),
}


def authorize(ghub, reauthorize=False, fromenv=False):
    """Authorize a user for GHub

    Keyword arguments:
    ghub -- the ghub object that needs authorization
    reauthorize -- performs authorization again (default False)
    """
    if fromenv:
        oauth_data = json.loads(os.environ["GHUB_CRED"])
        ghub.oauth_data = oauth_data
        ghub.github.token = oauth_data
        return True
    if not os.path.isfile(ghub.data_path / ghub.auth_filename) or reauthorize:
        authorization_base_url = "https://github.com/login/oauth/authorize"
        token_url = "https://github.com/login/oauth/access_token"
        authorization_url, _ = ghub.github.authorization_url(authorization_base_url)
        webbrowser.open(authorization_url)
        print("Please visit this site and grant access: {}".format(authorization_url))
        redirect_response = input(
            "Please enter the URL you were redirected to after granting access: "
        )
        try:
            response = ghub.github.fetch_token(
                token_url,
                client_secret=ghub.client_secret,
                authorization_response=redirect_response,
            )
        except Exception as e:
            print(e)
            print(
                "Network Error. Make sure you have a working internet connection and try again."
            )
            sys.exit(1)
        if not os.path.isdir(ghub.data_path):
            os.makedirs(ghub.data_path)
        data_file = open(ghub.data_path / ghub.auth_filename, "w+")
        json.dump(response, data_file)
        data_file.close()
        os.chmod(ghub.data_path / ghub.auth_filename, stat.S_IRUSR | stat.S_IWUSR)
        ghub.oauth_data = response
        return True
    else:
        data_file = open(ghub.data_path / ghub.auth_filename, "r")
        oauth_data = json.loads(data_file.read())
        data_file.close()
        ghub.oauth_data = oauth_data
        ghub.github.token = oauth_data
        return True


def get_user(ghub, user):
    url = ghub.api_url + ghub.endpoints["users"] + user
    response = ghub.github.get(url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "user"
        ghub.context.location = user
        ghub.context.cache = response.json()
        return True
    return False


def get_org(ghub, org):
    url = ghub.api_url + ghub.endpoints["orgs"] + org
    response = ghub.github.get(url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "org"
        ghub.context.location = org
        ghub.context.cache = response.json()
        return True
    return False


def get_user_tabs(ghub, tab=""):
    tabs = ["repos", "stars", "followers", "following", "notifications"]
    if tab not in tabs:
        print("{} is not a valid user tab".format(tab))
        return
    if ghub.context.context == "root":
        if tab == "":
            ghub.context.set_context_to_root()
        elif tab == "repos":
            response = ghub.github.get(ghub.api_url + ghub.endpoints["user"] + "/repos")
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = ghub.user["login"] + "/" + "repos"
                ghub.context.context = "repos"
            else:
                print("Error getting data - " + response.status_code)
        elif tab == "stars":
            response = ghub.github.get(
                ghub.api_url + ghub.endpoints["user"] + "/starred"
            )
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = ghub.user["login"] + "/" + "stars"
                ghub.context.context = "stars"
            else:
                print("Error getting data - " + response.status_code)
        elif tab == "followers" or tab == "following":
            response = ghub.github.get(
                ghub.api_url + ghub.endpoints["user"] + "/" + tab
            )
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = ghub.user["login"] + "/" + tab
                ghub.context.context = tab
            else:
                print("Error getting data - " + response.status_code)
        elif tab == "notifications":
            response = ghub.github.get(ghub.api_url + ghub.endpoints["notifications"])
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = ghub.user["login"] + "/" + tab
                ghub.context.context = tab
            else:
                print("Error getting data - " + response.status_code)
    elif ghub.context.context == "user" or ghub.context.context == "org":
        if tab == "":
            ghub.context.set_context_to_root()
        elif tab == "repos":
            if ghub.context.context == "user":
                url = (
                    ghub.api_url
                    + ghub.endpoints["users"]
                    + ghub.context.location
                    + "/repos"
                )
            else:
                url = (
                    ghub.api_url
                    + ghub.endpoints["orgs"]
                    + ghub.context.location
                    + "/repos"
                )
            response = ghub.github.get(url)
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = (
                    ghub.context.prev_context.location + "/" + "repos"
                )
                ghub.context.context = "repos"
            else:
                print("Error getting data - " + response.status_code)
        elif tab == "stars":
            response = ghub.github.get(
                ghub.api_url
                + ghub.endpoints["users"]
                + ghub.context.location
                + "/starred"
            )
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = (
                    ghub.context.prev_context.location + "/" + "star"
                )
                ghub.context.context = "stars"
            else:
                print("Error getting data - " + response.status_code)
        elif tab == "followers" or tab == "following":
            response = ghub.github.get(
                ghub.api_url
                + ghub.endpoints["users"]
                + ghub.context.location
                + "/"
                + tab
            )
            if response.status_code == 200:
                ghub.context = Context(prev_context=ghub.context)
                ghub.context.cache = response.json()
                ghub.context.location = ghub.context.prev_context.location + "/" + tab
                ghub.context.context = tab
            else:
                print("Error getting data - " + response.status_code)
    else:
        pass


def get_latest_commit(ghub, repo, branch="master"):
    api_url = "https://api.github.com/repos/{}/branches/{}".format(repo, branch)
    response = ghub.github.get(api_url)
    if response.status_code == 200:
        response = response.json()
        return response["commit"]["commit"]
    else:
        return False


def get_tree(ghub, repo=None, branch="master", tree_url=None):
    if tree_url == None:
        latest_commit = get_latest_commit(ghub, repo, branch)
        if latest_commit == False:
            return False
        response = ghub.github.get(latest_commit["tree"]["url"])
        if response.status_code == 200:
            response = response.json()
            return response
        return False
    else:
        response = ghub.github.get(tree_url)
        if response.status_code == 200:
            response = response.json()
            return response


def get_blob(ghub, blob_url):
    response = ghub.github.get(blob_url)
    if response.status_code == 200:
        return response.json()
    return False


def clone_repo(ghub, dir, repo_name=None):
    print("Preparing to clone...")
    if repo_name == None:
        repo_name = "/".join(ghub.context.location.split("/")[:2])
    if dir[0] == "~":
        dir = os.path.expanduser("~") + dir[1:]
    dir = dir + "/" + repo_name.split("/")[1]
    try:
        Repo.clone_from("https://github.com/" + repo_name, dir)
        print("{} cloned to {}".format(repo_name, dir))
        return True
    except Exception as e:
        print(e)
        return False


def star_repo(ghub, repo_name=None):
    print("Starring repo...")
    if repo_name == None:
        repo_name = ghub.context.location
    star_url = ghub.api_url + ghub.endpoints["user"] + "/" + "starred/" + repo_name
    response = ghub.github.get(star_url)
    if response.status_code == 204:
        print("Repo is already starred.")
    elif response.status_code == 404:
        resp = ghub.github.put(star_url)
        if resp.status_code == 204:
            print("{} starred".format(repo_name))
        else:
            print("Error starring repo")


def unstar_repo(ghub, repo_name=None):
    print("Unstarring repo...")
    if repo_name == None:
        repo_name = ghub.context.location
    star_url = ghub.api_url + ghub.endpoints["user"] + "/" + "starred/" + repo_name
    response = ghub.github.get(star_url)
    if response.status_code == 204:
        resp = ghub.github.delete(star_url)
        if resp.status_code == 204:
            print("{} unstarred".format(repo_name))
        else:
            print("Error unstarring repo")
    elif response.status_code == 404:
        print("Repo is not starred.")


def watch_repo(ghub, repo_name=None):
    print("Subscribing to repo...")
    if repo_name == None:
        repo_name = ghub.context.location
    watch_url = ghub.api_url + ghub.endpoints["repos"] + repo_name + "/subscription"
    response = ghub.github.get(watch_url)
    if response.status_code == 200:
        print("You are already watching this repo.")
    elif response.status_code == 404:
        resp = ghub.github.put(watch_url)
        if resp.status_code == 200:
            print("Watching {}".format(repo_name))
        else:
            print("Error subscribing to repo")


def unwatch_repo(ghub, repo_name=None):
    print("Unsubscribing repo...")
    if repo_name == None:
        repo_name = ghub.context.location
    watch_url = ghub.api_url + ghub.endpoints["repos"] + repo_name + "/subscription"
    response = ghub.github.get(watch_url)
    if response.status_code == 200:
        resp = ghub.github.delete(watch_url)
        if resp.status_code == 204:
            print("{} unsubscribed".format(repo_name))
        else:
            print("Error unsubscribing to repo")
    elif response.status_code == 404:
        print("You are not watching this repo.")


def fork_repo(ghub, repo_name=None):
    print("Forking Repo...")
    if repo_name == None:
        repo_name = ghub.context.location.split("/")
        repo_name = "/".join(repo_name[:2])
    true_repo_name = repo_name.split("/")[1]
    forked_url = (
        ghub.api_url
        + ghub.endpoints["repos"]
        + ghub.get_user_username()
        + "/"
        + true_repo_name
    )
    response = ghub.github.get(forked_url)
    if response.status_code == 200:
        print("Cannot fork. Repo Already Exists.")
        return False
    print("Repo is being forked. Please wait for it to complete.", end="")
    response = ghub.github.post(
        ghub.api_url + ghub.endpoints["repos"] + repo_name + "/forks"
    )
    if response.status_code == 202:
        print(
            "\nForking complete. Forked repo to {}".format(
                ghub.get_user_username() + "/" + true_repo_name
            )
        )
        return True
    else:
        print("Error while trying fork.")
        return False


def get_prs(ghub, repo_name=None):
    if repo_name == None:
        repo_name = "/".join(ghub.context.location.split("/")[:2])
    pr_url = ghub.api_url + ghub.endpoints["repos"] + repo_name + "/pulls"
    response = ghub.github.get(pr_url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "pull_requests"
        ghub.context.location = repo_name + "/pull_requests"
        ghub.context.cache = response.json()
        return True
    return False


def get_pr(ghub, pr_no):
    if not pr_no.isdigit():
        print("Invalid PR number")
        return False
    repo_name = "/".join(ghub.context.location.split("/")[:2])
    pr_url = ghub.api_url + ghub.endpoints["repos"] + repo_name + "/pulls/" + pr_no
    response = ghub.github.get(pr_url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "pull_request"
        ghub.context.location = repo_name + "/pull_requests/" + pr_no
        ghub.context.cache = response.json()
        return True
    elif response.status_code == 404:
        print("No PR found with PR number {}".format(pr_no))
    return False


def get_pr_info(ghub, info_type="comments"):
    info_url = ghub.context.cache["_links"][info_type]["href"]
    response = ghub.github.get(info_url)
    return response.json(), response.status_code


def get_issues(ghub, repo_name=None):
    if repo_name == None:
        repo_name = "/".join(ghub.context.location.split("/")[:2])
    issue_url = ghub.api_url + ghub.endpoints["repos"] + repo_name + "/issues"
    response = ghub.github.get(issue_url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "issues"
        ghub.context.location = repo_name + "/issues"
        ghub.context.cache = response.json()
        return True
    return False


def get_issue(ghub, issue_no):
    if not issue_no.isdigit():
        print("Invalid issue number")
        return False
    repo_name = "/".join(ghub.context.location.split("/")[:2])
    issue_url = (
        ghub.api_url + ghub.endpoints["repos"] + repo_name + "/issues/" + issue_no
    )
    response = ghub.github.get(issue_url)
    if response.status_code == 200:
        ghub.context = Context(prev_context=ghub.context)
        ghub.context.context = "issue"
        ghub.context.location = repo_name + "/issues/" + issue_no
        ghub.context.cache = response.json()
        return True
    elif response.status_code == 404:
        print("No issue found with issue number {}".format(issue_no))
    return False


def get_issue_info(ghub, info_type="comments"):
    info_url = ghub.context.cache["{}_url".format(info_type)]
    response = ghub.github.get(info_url)
    return response.json(), response.status_code

[(102, 'json.loads', 'json.loads', False, 'import json\n'), (110, 'webbrowser.open', 'webbrowser.open', False, 'import webbrowser\n'), (130, 'json.dump', 'json.dump', False, 'import json\n'), (132, 'os.chmod', 'os.chmod', False, 'import os\n'), (321, 'git.Repo.clone_from', 'Repo.clone_from', False, 'from git import Repo\n'), (106, 'os.path.isfile', 'os.path.isfile', False, 'import os\n'), (127, 'os.path.isdir', 'os.path.isdir', False, 'import os\n'), (128, 'os.makedirs', 'os.makedirs', False, 'import os\n'), (318, 'os.path.expanduser', 'os.path.expanduser', False, 'import os\n'), (126, 'sys.exit', 'sys.exit', False, 'import sys\n')]