#!/usr/bin/env python3
# pylint: disable=invalid-name
"""Backup a Git repositories namespace to my GitLab instance.

Which means creating a namespace in GitLab, creating a project for every
repository in the namespace, adding a remote to the repository and pushing
everything to that project.

In this context, a namespace is a directory under ~/Repositories.
"""

import argparse
import os
import os.path
import pathlib
import sys

import gitlab.exceptions  # pylint: disable=import-error
import sh  # pylint: disable=import-error
from sh.contrib import git  # pylint: disable=import-error

sys.path.append(os.path.expanduser("~/Documents/bin"))

import rcfiles.git  # noqa: E402 pylint: disable=wrong-import-position
import rcfiles.gitlab  # noqa: E402 pylint: disable=wrong-import-position


def namespace_path(namespace):
    """Returns the full path to the namespace.

    Raises an exception if the path doesn't exits or isn't a directory.
    """
    path = pathlib.Path(os.path.expanduser("~/Repositories/" + namespace))
    if not path.exists():
        raise argparse.ArgumentTypeError(f"Path {path} does not exit.")
    if not path.is_dir():
        raise argparse.ArgumentTypeError(f"Path {path} is not a directory.")
    return path


def list_repositories(namespace):
    """Returns a list of paths under the namespace that are Git
    repositories."""
    return [x for x in namespace.iterdir() if rcfiles.git.is_repo(x)]


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("namespace", type=namespace_path)
    args = parser.parse_args()

    with rcfiles.gitlab.connect() as conn:
        try:
            group = conn.groups.get(args.namespace.name)
            print(
                (
                    f"Using existing group id: {group.id},"
                    f" name: {group.name}, path: {group.path}."
                ),
                file=sys.stderr,
            )
        except gitlab.exceptions.GitlabGetError:
            group = conn.groups.create(
                {
                    "name": args.namespace.name,
                    "path": rcfiles.gitlab.name_to_path(args.namespace.name),
                    "visibility": "internal",
                }
            )
            print(
                (
                    f"Created new group id: {group.id},"
                    f"name: {group.name}, path: {group.path}."
                ),
                file=sys.stderr,
            )
        for repo in list_repositories(args.namespace):
            try:
                project = conn.projects.get(f"{group.path}/{repo.name}")
                print(
                    (
                        f"Using existing project id: {project.id},"
                        f" name: {project.name}, path: {project.path}."
                    ),
                    file=sys.stderr,
                )
            except gitlab.exceptions.GitlabGetError:
                project = conn.projects.create(
                    {"name": repo.name, "namespace_id": group.id}
                )
                print(
                    (
                        f"Created new project id: {project.id},"
                        f"name: {project.name}, path: {project.path}."
                    ),
                    file=sys.stderr,
                )
            with sh.pushd(repo):
                if "shore.co.il" in git.remote().splitlines():
                    print(
                        f"Setting the remote URL in {repo.name}.",
                        file=sys.stderr,
                    )
                    git.remote(
                        "set-url", "shore.co.il", project.ssh_url_to_repo
                    )
                else:
                    print(
                        f"Adding remote in {repo.name}.",
                        file=sys.stderr,
                    )
                    git.remote("add", "shore.co.il", project.ssh_url_to_repo)
                print(
                    f"Pushing to {project.ssh_url_to_repo}.",
                    file=sys.stderr,
                )
                git.push("--all", "shore.co.il")
