#!/usr/bin/env python3
import os
import sys
import getpass
import pathlib
import logging
import argparse
import gzip
import configparser
import subprocess

import requests

import tarfile
import gnupg

## argparse arguments
parser = argparse.ArgumentParser(description="Python backup utility")

backutil_config = str(pathlib.Path.home()) + '/.backutil.conf'

## Backup subparser
parser.add_argument('--path', help='path(s) to backup', metavar='PATH', nargs='+', required='True')
parser.add_argument('--dest', help='destination of backup', metavar='DEST', required='True')
parser.add_argument('--webdav', help='WebDav URL to upload to', metavar='URL')
parser.add_argument('--remote', help='Remote WebDav path to upload to', metavar='REMOTE PATH')
parser.add_argument('--encrypt', help='Use gpg to encrypt file', metavar='RECIPIENT')
parser.add_argument('-z', '--zip', help='use gzip to compress the backup file', action="store_true")
parser.add_argument('--rm', help='remove local backup file', action="store_true")
parser.add_argument('-v', '--verbose', help='enable verbose output', action="store_true")
parser.add_argument('-q', '--quiet', help='suppress output', action="store_true")
parser.add_argument('-i', '--insecure', help='ignore SSL certificate warnings', action="store_true")

args = parser.parse_args()

log = logging.getLogger(__name__)


def check_dest(dest):
    dir = os.path.dirname(dest)
    if not os.path.isdir(dir):
        log.error('Invalid dest: ' + dest)
        sys.exit(1)

def webdav_auth(config_file):
    config = configparser.ConfigParser()
    global username
    global password
    if os.path.isfile(config_file):
        config.read(config_file)
        try:
            if config['WEBDAV']['Username']:
                username = str(config['WEBDAV']['Username'])
            if config['WEBDAV']['Command']:
                password = subprocess.check_output(config['WEBDAV']['Command'], shell=True)
                password = str(password.decode("utf-8"))
                password = password.rstrip()
            elif config['WEBDAV']['Password']:
                password = str(config['WEBDAV']['Password'])
                password = password.rstrip()
        except:
            username = input('WebDav Username: ')
            password = getpass.getpass('WebDav Password: ')
    else:
        username = input('WebDav Username: ')
        password = getpass.getpass('WebDav Password: ')

def webdav_upload(file, url, username, password):
    if not 'remote.php/dav' in url:
        url = url + '/remote.php/dav'
    url = url + '/files/' + username + '/'
    if args.remote:
        webdav_path = str(args.remote)
    else:
        webdav_path = input('Remote Path: ')
    url = url + webdav_path
    if not args.encrypt:
        if args.zip:
            f = gzip.open(file, 'rb')
            file_data = f.read()
            if not args.insecure:
                response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'application/zip'}, params={'file': str(file)}) 
            else:
                response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'application/zip'}, params={'file': str(file)}, verify=False) 
        else:
            with open(file) as fh:
                file_data = fh.read()
                if not args.insecure:
                    response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'text/plain'}, params={'file': str(file)}) 
                else:
                    response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'text/plain'}, params={'file': str(file)}, verify=False) 
    else:
        with open(file) as fh:
            file_data = fh.read()
            if not args.insecure:
                response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'application/pgp-encrypted'}, params={'file': str(file)}) 
            else:
                response = requests.put(str(url), data=file_data, auth=(str(username), str(password)), headers={'content-type':'application/pgp-encrypted'}, params={'file': str(file)}, verify=False) 
            

def encrypt(destination, recipient):
    global new_dest
    gpg = gnupg.GPG(gnupghome=str(pathlib.Path.home()) + '/.gnupg')
    gpg.encoding = 'utf-8'
    if args.zip:
        f = gzip.open(str(destination), 'rb')
        file_data = f.read()
        if not '.gpg' in destination:
            outfile = destination + '.gpg'
        else:
            outfile = destination
        gpg.encrypt(file_data, recipients=str(recipient), output=outfile)
        os.remove(destination)
        new_dest = outfile
    else:
        with open(str(destination)) as fh:
            file_data = fh.read()
            if not '.gpg' in destination:
                outfile = destination + '.gpg'
            else:
                outfile = destination
            gpg.encrypt(file_data, recipients=str(recipient), output=outfile)
            os.remove(destination)
            new_dest = outfile


def backup(paths, dest):
    if args.zip:
        tar = tarfile.open(name=dest, mode='w:gz')
    else:
        tar = tarfile.open(name=dest, mode='w')
    for path in paths:
        if os.path.isfile(path):
            path_status = 'True'
        elif os.path.isdir(path):
            path_status = 'True'
        else:
            log.error('Invalid path. Skipping: ' + path)
            path_status = 'False'
        if path_status == 'True':
            if args.verbose:
                if args.quiet:
                    log.error('Cannot use verbose and quiet arguments simultaneously.')
                    log.info('Quitting.')
                    sys.exit(1)
                log.info(path + ' => ' + dest)
            elif args.quiet:
                if args.verbose:
                    log.error('Cannot use verbose and quiet arguments simultaneously.')
                    log.info('Quitting.')
                    sys.exit(1)
            else:
                log.info(path)
            tar.add(path)
    tar.close()


def main():
    check_dest(args.dest)
    dest = args.dest
    backup(args.path, dest)
    if args.encrypt:
        encrypt(dest, str(args.encrypt))
        dest = new_dest
    if args.webdav:
        webdav_auth(backutil_config)
        webdav_upload(dest, args.webdav, username, password)
    if args.rm:
        os.remove(dest)

if __name__ == '__main__':
    main()
