#!/usr/bin/env python3

import os
import re
import sys
import requests
from clint.textui import colored, puts


class GithubSectory():
    ''' docstring for GithubSectory : Python script to download Github Project Subdirectory! '''

    def __init__(self):
        self.dir = ''
        self.link = ''
        self.repo = ''
        self.CONST = CONST()
        self.gh = "https://github.com/"
        self.ghapi = "https://api.github.com/repos/"

    def createLinkFromSystemArgs(self, args):
        ''' Method is used to parse the arguments given by user '''

        # If no arguments are passed, display usage info and exit.
        try:
            self.link = args[1]
        except IndexError:
            puts(colored.yellow(self.CONST.USAGE_INFORMATION))
            sys.exit(0)

        # Link of the directory is passed as parameter
        if re.search(r'github.com', self.link):

            puts(colored.magenta("[ Validating Input URL ]"))

            if len(self.link.split("/")) < 7:
                puts(colored.yellow(self.CONST.NORMAL_LINK_ERROR))
                sys.exit(0)
            else:
                self.link = self.link.replace(self.gh, self.ghapi)
                self.link = self.link.replace('tree', 'contents')
                linkList = self.link.split('/')
                self.repo = self.dir = linkList[8]
                self.link = self.link.replace(linkList[7] + '/', '')
                self.link = self.link + '/?ref=' + linkList[7]

        else:

            # Details are passed as parameters.

            puts(colored.magenta("[ Validating Input Parameters ]"))

            try:
                for index, arg in enumerate(args):
                    if arg == "-u":
                        name = args[index+1]
                    if arg == "-r":
                        self.repo = args[index+1]
                    if arg == "-d":
                        self.dir = args[index+1]
                    if arg == "-b":
                        branch = args[index+1]
            except IndexError:
                puts(colored.red(self.CONST.VALUE_MISSING_ERROR))
                sys.exit(0)

            try:
                self.link = self.ghapi + name
            except Exception:
                puts(colored.red(self.CONST.USER_VALUE_ERROR))
                sys.exit(0)

            try:
                self.link = self.link + "/" + self.repo
            except Exception:
                puts(colored.red(self.CONST.REPOSITORY_VALUE_ERROR))
                sys.exit(0)

            try:
                self.link = self.link + "/contents/" + self.dir

                try:
                    self.link = self.link + "?ref=" + branch
                except UnboundLocalError:
                    pass

            except UnboundLocalError:
                self.link = self.gh + name + "/" + self.repo + ".git"
                puts(colored.yellow(
                    self.CONST.NORMAL_PARAM_ERROR.format(url=self.link)))
                sys.exit(0)

    def getDirectoryContent(self):
        ''' Method to fetch folder content from generated link '''

        puts(colored.yellow("[ Fetching folder content ]"))

        try:
            headers = {
                'Authorization': '13678a6cb0a39b4bf9d3fa69796f6b304eaa1c4d'
            }

            self.response = requests.request(
                "GET", self.link, headers=headers, data={}).json()

            if type(self.response) is dict and self.response['message'] == 'Not Found':
                raise Exception()

        except (requests.HTTPError, Exception):
            puts(colored.red(self.CONST.PRIVATE_REPO_URL_ERROR))
            sys.exit(0)

        if not os.path.exists(self.dir):
            os.makedirs(self.dir)

        self.path = os.path.join(os.getcwd(), self.dir)

    def downloadFile(self, filepath, folderdata):
        ''' Create direcotry and download file using files json '''

        for file in folderdata:
            if file['type'] == 'file':
                fileCreate = open(os.path.join(filepath, file['name']), 'a+')
                fileCreate.write(requests.get(file['download_url']).text)
                fileCreate.close()
            else:
                changedPath = os.path.join(filepath, file['name'])
                if not os.path.exists(changedPath):
                    os.makedirs(changedPath)
                newFileData = requests.get(file['url']).json()
                self.downloadFile(changedPath, newFileData)

    def start(self):
        ''' Method is used to start the execution '''

        self.createLinkFromSystemArgs(sys.argv)

        self.getDirectoryContent()

        puts(colored.yellow('[ Downloading all required files ]'))

        self.downloadFile(self.path, self.response)

        puts(colored.green('\n[ Finished ]'))


class CONST(object):
    USAGE_INFORMATION = """
        \nCLI for downloading sub-directory of any Github repository.
        \nOptions:
        \t-r, name of the repository where the folder/directory is present.
        \t-d, name of the directory that you wish to download.
        \t-u, username/organisation name of owner of repository.

        \t-b, branch name of the repository, default is master [OPTIONAL].

        \nUsage:
        \t1. Pass the directory link as an argument-
        \t\t$ github-sectory <github-link-to-directory>

        \t2. Pass the details as an arguments specified below-
        \t\t$ github-sectory -u <username> -r <repository-name> -d <directory-name> -b <branch-name>
    """

    NORMAL_LINK_ERROR = "\nNormal Link, use git commands to clone repository!"

    VALUE_MISSING_ERROR = "\nError : Value for the givin param is not found!"

    USER_VALUE_ERROR = "\nError : User/Organisation not mentioned. Truncating process!"

    REPOSITORY_VALUE_ERROR = "\nError : Repository not mentioned. Truncating process!"

    NORMAL_PARAM_ERROR = "\nUse this URL [ {url} ] to clone the repository!"

    PRIVATE_REPO_URL_ERROR = "\nInvalid URL! Maybe private repo"

    def __setattr__(self, *_):
        pass


if __name__ == '__main__':
    GithubSectory().start()
