__version__ = '0.1.0'

PROG_NAME = 'GitlabInstaller'

APT_DEPS = [ 'curl', 'openssh-server', 'ca-certificates' ]

log = None

updated_apt = None

# Introduce a global variable called 'cache_max_age' which will be used (in the case of unexpected delays between
# program operations, etc) should contain the time (in seconds) that should pass between program-calls to 'apt
# update'. This will help limit unnecessary long cache updates happening several times a minute (wasting time and
# resources) while at the same-time encouraging a healthy, updated cache should a distracted user leave the program
# waiting at an unexpected prompt for a while.

cache_max_age = 1200 # No weight yet

def do_apt_update(time_override=False):
    if not time_override:

        # ToDO (Function Task List):
        #   - Pull time last updated from 'updated_apt' global variable
        #   - Convert this time into seconds-since-epoch?
        #   - Pull current time (time.now.strftime?)
        #   - Convert this time into seconds-since-epoch?

        pass
    pass


def write_sources_file(path=None):
    # Import datetime, for timestamping the comment in our sources file
    import datetime

    # Import logging.getLogger to create a logger for this function.
    from logging import getLogger

    _log_ = getLogger(PROG_NAME)
    _log_.debug(f'Logger initialized for {PROG_NAME}')

    # Generate a string that will act as a comment in the generated sources file, explaining why and when the file was
    # created.
    comment = f'# This file was auto-generated by ' \
              f'# gitlab-installer from Inspyre Softworks ' \
              f'# at {datetime.datetime.now()}\n\n'
    ln_1 = 'deb https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu/ bionic main\n'
    ln_2 = 'deb-src https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu/ bionic main\n'

    # The strings defined above are lines that will be placed (in this order: comment, ln_1,
    # ln_2) in gitlab_gitlab-ce.list in /etc/apt/sources.list.d

    ln_queue = [ comment, ln_1, ln_2 ]

    with open('/etc/apt/sources.list.d/gitlab_gitlab-ce.list', 'w') as sources_file:
        for q_line in ln_queue:
            sources_file.write(q_line)
            _log_.info('Wrote sources file for Ubuntu Bionic, this is the recommended route for Ubuntu 20.04 LTS Focal')

class AptInstaller:

    def do_install(self, package):
        pass

    def do_uninstall(self, package):
        pass

    @staticmethod
    def do_auto_remove():
        """

        This will call 'apt autoremove -y'

        Returns:

        """
        pass

    def failsafe(self):

        # ToDo:
        #   - In docstring below, should describe the process by which this function "undoes" installs that have
        #     already been completed.
        #   - Introduce function.

        """

        A function to be called when the program catches a signal-interrupt which can undo any installs that were
        done already.

        Returns:

        """
        pass

    def __init__(self):
        """

        Initialize a new instance of AptInstaller.

        """

        # Import logging.getLogger and have it get us our InspyLogger
        from logging import getLogger

        self.logname = f'{PROG_NAME}.AptInstaller'
        log = getLogger(self.logname)
        log.debug(f'Logger initialized for {self.logname}')




def apt_check_local(pkg):
    pass


def install_pkg(pkg):
    """

    Args:
        pkg (str): A string containing the name of the package you want to install via apt.

    """
    if not apt_check_local(pkg):
        apt_install(pkg)


def apt_install(pkgs):
    """

    Pass this a list of packages on apt you need installed, and this function will drop that package list onto apt's
    install command following an 'apt update' instruction.

    Args:
        pkgs (List): A list of packages (or even a list containing one package) that need to be installed.
    """

    from subprocess import Popen, PIPE, STDOUT
    from logging import getLogger

    _log_ = getLogger(f'{PROG_NAME}.AptInstall')
    info = _log_.info

    proc = Popen(f'apt update && apt install -y {" ".join(APT_DEPS)}', stdout=PIPE, stderr=STDOUT, shell=True,
                 universal_newlines=True)
    stdout = [ ]

    installing = False
    cur_install = None
    missing = None
    while True:
        line = proc.stdout.readline()
        stdout.append(line)
        _log_.info(line)

        if line.startswith('Selecting previously') and line.split()[ -1 ] in APT_DEPS:
            _log_.info(f'Installing {line.split()[ -1 ]}...')

        if installing:
            missing = line
            info(f'The following packages are missing: {missing}')
            installing = False

        if line.startswith('The following NEW'):
            installing = True

        if line.startswith('ca-certificates is already '):
            add_present_dep('ca-certificates')
        if line.startswith('curl is already '):
            add_present_dep('curl')
        if line.startswith('openssh-server is already '):
            add_present_dep('openssh-server')
        if line == '' and proc.poll() is not None:
            break

    dep_count = len(APT_DEPS)
    already_present_count = len(already_present)
    info(f'{already_present_count}/{dep_count} apps already present on system')




def pingtest(host=None):
    import os

    # Assign h_name to the keyword argument 'host'
    h_name = host

    # If the keyword argument 'host' is None-type; ping the dev's website
    if host is None:
        h_name = 'inspyre.tech'

    res = os.system("ping -c 1 " + h_name)

    # and then check the response...
    if res == 0:
        log.info(f'{h_name}, is reachable!')
        return True
    else:
        log.warning(f'{h_name}, is unreachable!')
        return False


already_present = [ ]


def add_present_dep(pkg):
    global already_present, log

    already_present.append(pkg)
    log.warning(f'{pkg} was already present on the system so it was not installed')


def main():
    global log, already_present

    # Import the logging library
    import inspy_logger

    # Import the library used to check user root status
    from os import geteuid

    # Import the libraries from subprocess we'll need
    from subprocess import Popen, PIPE, STDOUT

    # Start logger object loaded into a variable
    log = inspy_logger.start(PROG_NAME, True)

    # Set an alias for the  logger's info function
    info = log.info

    info('Checking privileges...')

    if not geteuid() == 0:
        # ToDo:
        #   - Create an exception that will be raised when this condition is met

        exit('You must run this program as root.')

    else:
        info('Permissions sufficient!')

    # Run a pingtest on the default host
    #
    # ToDo:
    #   - Create command-line argument to change pingtest's host to ping
    #   - Create command-line argument to disable this action
    #   - This should raise an actual custom exception
    if not pingtest():
        log.error('No internet connection.')
        exit('There is no internet connection, please check your network and try again.')

    # Install Gitlab dependencies and log the output of this process.
    apt_install(APT_DEPS)

    log.info(f'Using cURL to install Gitlab')

    download_installer = Popen('curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh '
                               '| bash',
                               shell=True, stdout=PIPE, stderr=STDOUT, universal_newlines=True)
    inst_stdout = [ ]
    out_keywords = [ 'Detected', 'Checking', 'Running', 'Installing', 'Importing', 'The repo' ]

    while True:
        i_line = download_installer.stdout.readline()
        fi_line = i_line.replace(' ', '')
        inst_stdout.append(i_line)
        if not fi_line == '':
            if i_line.startswith(tuple(out_keywords)):
                info(i_line)
            else:
                print(i_line)

        if i_line == '' and download_installer.poll() is not None:
            break

    installer = Popen('EXTERNAL_URL="https://gitlab.example.com" apt-get install gitlab-ce',
                      shell=True, stdout=PIPE, stderr=STDOUT, universal_newlines=True)

    in_stdout = [ ]

    while True:
        in_line = installer.stdout.readline()
        fin_line = in_line.replace(' ', '')

        if in_line.startswith('E:'):
            log.warning('Could not find package gitlab-ce in newly added repository')
            write_sources_file()
        if not fin_line == '':
            if in_line.startswith(tuple(out_keywords)):
                info(in_line)
            else:
                print(in_line)

        if in_line == '' and installer.poll() is not None:
            break

        in_stdout.append(in_line)
    apt_install('gitlab-ce')


if __name__ == '__main__':
    main()
    log.info('Program exited successfully!')
