#!/usr/bin/python
from __future__ import print_function
import glob
import errno
import fnmatch
import random
import datetime
import hashlib
import signal
import shutil
import string
import re
import pipes
import subprocess
import os
import argparse
import time
from contextlib import contextmanager
import sys
import atexit
import math

input = raw_input
orig_dir = os.path.abspath(".")

def format_process_call(*a, **kw):
    res = []
    for x in a:
        res.append(repr(x))
    for k, v in kw.items():
        res.append("{}={}".format(k, repr(v)))
    return ", ".join(res)

def process_call(*a, **kw):
    log("subprocess.call({})".format(format_process_call(*a, **kw)), level=2)
    return subprocess.call(*a, **kw)
def process_check_call(*a, **kw):
    log("subprocess.check_call({})".format(format_process_call(*a, **kw)), level=2)
    return subprocess.check_call(*a, **kw)
def process_check_output(*a, **kw):
    log("subprocess.check_output({})".format(format_process_call(*a, **kw)), level=2)
    return subprocess.check_output(*a, **kw)
def process_open(*a, **kw):
    log("subprocess.Popen({})".format(format_process_call(*a, **kw)), level=2)
    return subprocess.Popen(*a, **kw)
red    = lambda: color(31)
green  = lambda: color(32)
yellow = lambda: color(33)
blue   = lambda: color(34)

parser = argparse.ArgumentParser()
parser.add_argument("-P", "--purge", action="store_true", help="delete entire vastai folder")
parser.add_argument("-l", "--logfile", default="vast_host_uninstall.log")
parser.add_argument("-v", "--verbose", action="count", default=0, help="increase verbosity")
parser.add_argument("-d", "--keep-docker", action="store_true", help="don't delete or ask to delete docker")
parser.add_argument("--no-keep-docker", action="store_true", help="delete docker without asking")
#parser.add_argument("-d", "--keep-xfs", action="store_true", help="don't delete or ask to delete xfs partition")
#parser.add_argument("--no-keep-xfs", action="store_true", help="delete xfs partition without asking; does nothing if docker is not also deleted")
args = parser.parse_args()
args.logfile = os.path.abspath(os.path.expanduser(args.logfile))
logfile = open(args.logfile, "a")
if "VAST_DEBUG" in os.environ and os.environ["VAST_DEBUG"].strip():
    try:
        args.verbose = int(os.environ["VAST_DEBUG"].strip())
    except ValueError:
        args.verbose = 10
    filtered_args = []
    for arg in sys.argv:
        if arg.startswith("-") and len(arg) > 1 and arg[1] != "-":
            flags = arg[1:]
            flags = flags.replace("q", "")
            if not flags:
                continue
            filtered_args.append("-" + flags)
        else:
            filtered_args.append(arg)
    filtered_args.append("-" + "v" * args.verbose)
    sys.argv = filtered_args
if args.verbose:
    os.environ["VAST_DEBUG"] = str(args.verbose)

def log(*a, **kw):
    level = kw.pop("level", 3)
    time = "[{} UTC]".format(datetime.datetime.utcnow().isoformat(" "))
    if args.verbose >= level:
        if args.verbose > 4:
            print(time, *a, **kw)
        else:
            print(*a, **kw)
        if args.verbose:
            sys.stdout.flush()
    kw["file"] = logfile
    logfile.flush()
    os.fsync(logfile.fileno())
    print(time, *a, **kw)
    logfile.flush()
    os.fsync(logfile.fileno())

if os.geteuid() != 0:
    args_ = ["sudo", sys.executable] + sys.argv
    log("This script must be run as root. Rerunning with `{args}`...".format(args=" ".join([pipes.quote(x) for x in args_])), level=0)
    proc = process_open(args_)
    try:
        sys.exit(proc.wait())
    except KeyboardInterrupt:
        proc.wait()
    sys.exit(1)

UPDATE_CRON="/etc/cron.d/vastai_kaalia_update"
SYSTEMD_SERVICE="/etc/systemd/system/vastai.service"
SYSTEMD_TLS_SERVICE="/etc/systemd/system/vastai_tls.service"

def try_rm(*filenames, **kwargs):
    glob_ = kwargs.get("glob", None)
    exclude = kwargs.get("exclude", None)
    if glob_ is not None:
        filenames = filenames + tuple(glob.glob(glob_))
    if exclude is not None:
        filenames = tuple(x for x in filenames if not fnmatch.fnmatch(x, exclude))
    for filename in filenames:
        log("Unlink", filename, level=1)
        try:
            os.unlink(filename)
            continue
        except OSError as e:
            if e.errno == errno.ENOENT:
                log("File didn't exist:", filename, level=2)
                continue
            elif e.errno == errno.EISDIR:
                # is a directory
                pass
            else:
                raise
        try:
            shutil.rmtree(filename)
        except OSError as e:
            if e.errno == errno.ENOENT:
                log("Directory didn't exist, which is weird because it did a second ago:", filename, level=1)
            raise

try_rm(UPDATE_CRON)
stderr = stdout = None
apt_q = "-y"
if args.verbose < 4:
    stderr = stdout = logfile
    apt_q = "-qq"
    
process_call(["systemctl", "stop", "vastai"],        stderr=stderr, stdout=stdout)
process_call(["systemctl", "stop", "vastai_tls"],    stderr=stderr, stdout=stdout)
process_call(["systemctl", "disable", "vastai"],     stderr=stderr, stdout=stdout)
process_call(["systemctl", "disable", "vastai_tls"], stderr=stderr, stdout=stdout)
try_rm(SYSTEMD_SERVICE)
try_rm(SYSTEMD_TLS_SERVICE)
try_rm("/usr/local/bin/vastai-run-update")
try_rm(glob="/var/lib/vastai_kaalia/*", exclude="*.log")
try_rm(glob="/var/lib/vastai_kaalia/.*", exclude="*history")
def ask_keep(keep_flag, nokeep_flag, message):
    keep = None
    if keep_flag:
        keep = True
        assert not nokeep_flag, "can't provide a keep and a no-keep flag at the same time"
    elif nokeep_flag:
        keep = False
        assert not keep_flag, "can't provide a keep and a no-keep flag at the same time"
    else:
        do_delete = raw_input(message + " [Y/n]").strip().lower() in ["y", "yes", "true", "delete"]
        keep = not do_delete
    return keep

keep_docker = ask_keep(args.keep_docker, args.no_keep_docker, "Remove docker?")
#keep_xfs    = ask_keep(args.keep_docker, args.no_keep_docker, "Remove docker?")

if not keep_docker:
    process_call(["systemctl", "stop", "docker"], stderr=stderr, stdout=stdout)
    process_call(["systemctl", "disable", "docker"], stderr=stderr, stdout=stdout)
    process_check_call(["apt-get", apt_q, "remove", "docker", "docker-engine", "docker.io", "docker-ce", "nvidia-docker2"], stdout=stdout, stderr=stderr)


print("Done. Docker, XFS, and Nvidia driver were not removed.")
