import json
import requests
import tempfile
import shutil
import subprocess
import os
import logging
import urllib.request
from multiprocessing import Pool
import app.easyCI.docker as docker

from contextlib import contextmanager

LOG = logging.getLogger(__name__)
CONFIG = "config.json"
PASSWORDS = "<PASSWORD>"
MAX_COMMENT_SIZE = 10000
PROCS = 1
REQUEST_TIMEOUT = 300


class QueueTask(object):
    host = None
    auth = None
    config = None
    id = None
    course = None
    task = None
    issue = None
    event = None
    files = None

    def __repr__(self):
        return repr(self.__dict__)


@contextmanager
def tmp_dir():
    t = tempfile.mkdtemp(dir="/var/tmp")
    try:
        yield t
    finally:
        shutil.rmtree(t)


def git_clone(repo, dst_dir):
    cmd = ["git", "clone", repo, dst_dir]
    LOG.info("RUN: %s", cmd)
    subprocess.check_call(cmd)


def prepare_dir(qtask, dirname):
    git_dir = os.path.join(dirname, "git")
    task_dir = os.path.join(dirname, "task")
    git_clone(qtask.course["repo"], git_dir)

    os.mkdir(task_dir)
    for url in qtask.files:
        filename = url.split('/')[-1]
        dst_path = os.path.join(task_dir, filename)
        LOG.info("Download '%s' -> '%s'", url, dst_path)
        print(url, dst_path)
        urllib.request.urlretrieve(url, dst_path)


def process_task(qtask):
    LOG.info("Proccess task %s", qtask.id)
    with tmp_dir() as dirname:
        prepare_dir(qtask, dirname)

        run_cmd = qtask.course["run_cmd"] + [qtask.task, "/task_dir/task"]
        #run_cmd = ["ls", "/task_dir/task"]
        ret = docker.execute(run_cmd, cwd="/task_dir/git", timeout=qtask.course["timeout"], user='root',
                             network='bridge', image=qtask.course["docker_image"],
                             volumes=["{}:/task_dir:ro".format(os.path.abspath(dirname))])

        status, retcode, is_timeout, output = ret

        LOG.info("Task %d done, status:%s, retcode:%d, is_timeout:%d",
                     qtask.id, status, retcode, is_timeout)

        LOG.info(" == Task %d output start", qtask.id)
        for line in output.split("\n"):
            LOG.info(line)
        LOG.info(" == Task %d output end", qtask.id)

        if len(output) > MAX_COMMENT_SIZE:
            output = output[:MAX_COMMENT_SIZE]
            output += u"\n...\nTRUNCATED"

        if is_timeout:
            output += u"\nTIMEOUT ({} sec)".format(qtask.course["timeout"])
        comment = u"[id:{}] Check DONE!<br>\nSubmited on {}<br>\n<pre>{}</pre>\n".format(qtask.id,
                                                                                     qtask.event_timestamp,
                                                                                     output)
        LOG.info("{}/api/v1/issue/{}/add_comment".format(qtask.host, qtask.issue_id))
        response = requests.post("{}/api/v1/issue/{}/add_comment".format(qtask.host, qtask.issue_id),
                                 auth=qtask.auth, data={"comment":comment.encode("utf-8")}, timeout=REQUEST_TIMEOUT)
        response.raise_for_status()
        LOG.info(" == Task %d DONE!, URL: %s/issue/%d", qtask.id, qtask.host, qtask.issue_id)

        return qtask


def load_passwords(filename=PASSWORDS):
    with open(filename) as config_fn:
        return json.load(config_fn)


def load_config(filename=CONFIG):
    with open(filename) as config_fn:
        config_arr = json.load(config_fn)
        config_dict = {}
        for course in config_arr:
            config_dict[course["course_id"]] = course

        return config_dict


def get_auth(passwords, host):
    host_auth = passwords[host]
    return (host_auth["username"], host_auth["password"])


config = load_config()
passwords = load_passwords()
pool = Pool(processes=PROCS)


def put_to_pool(task):
    course_id = task["course_id"]
    course = config[course_id]
    auth = get_auth(passwords, course["host"])
    files = task["files"]

    qtask = QueueTask()
    qtask.host = course["host"]
    qtask.auth = auth
    qtask.course = course
    qtask.task = task["title"]
    qtask.issue_id = task["issue_id"]
    qtask.files = files
    qtask.id = task["event"]["id"]
    qtask.event_timestamp = task["event"]["timestamp"]
    print(qtask)
    pool.apply_async(process_task, args=(qtask,))

import json
import requests
import tempfile
import shutil
import subprocess
import os
import logging
import urllib.request
from multiprocessing import Pool
import app.easyCI.docker as docker

from contextlib import contextmanager

LOG = logging.getLogger(__name__)
CONFIG = "config.json"
PASSWORDS = "<PASSWORD>"
MAX_COMMENT_SIZE = 10000
PROCS = 1
REQUEST_TIMEOUT = 300


class QueueTask(object):
    host = None
    auth = None
    config = None
    id = None
    course = None
    task = None
    issue = None
    event = None
    files = None

    def __repr__(self):
        return repr(self.__dict__)


@contextmanager
def tmp_dir():
    t = tempfile.mkdtemp(dir="/var/tmp")
    try:
        yield t
    finally:
        shutil.rmtree(t)


def git_clone(repo, dst_dir):
    cmd = ["git", "clone", repo, dst_dir]
    LOG.info("RUN: %s", cmd)
    subprocess.check_call(cmd)


def prepare_dir(qtask, dirname):
    git_dir = os.path.join(dirname, "git")
    task_dir = os.path.join(dirname, "task")
    git_clone(qtask.course["repo"], git_dir)

    os.mkdir(task_dir)
    for url in qtask.files:
        filename = url.split('/')[-1]
        dst_path = os.path.join(task_dir, filename)
        LOG.info("Download '%s' -> '%s'", url, dst_path)
        print(url, dst_path)
        urllib.request.urlretrieve(url, dst_path)


def process_task(qtask):
    LOG.info("Proccess task %s", qtask.id)
    with tmp_dir() as dirname:
        prepare_dir(qtask, dirname)

        run_cmd = qtask.course["run_cmd"] + [qtask.task, "/task_dir/task"]
        #run_cmd = ["ls", "/task_dir/task"]
        ret = docker.execute(run_cmd, cwd="/task_dir/git", timeout=qtask.course["timeout"], user='root',
                             network='bridge', image=qtask.course["docker_image"],
                             volumes=["{}:/task_dir:ro".format(os.path.abspath(dirname))])

        status, retcode, is_timeout, output = ret

        LOG.info("Task %d done, status:%s, retcode:%d, is_timeout:%d",
                     qtask.id, status, retcode, is_timeout)

        LOG.info(" == Task %d output start", qtask.id)
        for line in output.split("\n"):
            LOG.info(line)
        LOG.info(" == Task %d output end", qtask.id)

        if len(output) > MAX_COMMENT_SIZE:
            output = output[:MAX_COMMENT_SIZE]
            output += u"\n...\nTRUNCATED"

        if is_timeout:
            output += u"\nTIMEOUT ({} sec)".format(qtask.course["timeout"])
        comment = u"[id:{}] Check DONE!<br>\nSubmited on {}<br>\n<pre>{}</pre>\n".format(qtask.id,
                                                                                     qtask.event_timestamp,
                                                                                     output)
        LOG.info("{}/api/v1/issue/{}/add_comment".format(qtask.host, qtask.issue_id))
        response = requests.post("{}/api/v1/issue/{}/add_comment".format(qtask.host, qtask.issue_id),
                                 auth=qtask.auth, data={"comment":comment.encode("utf-8")}, timeout=REQUEST_TIMEOUT)
        response.raise_for_status()
        LOG.info(" == Task %d DONE!, URL: %s/issue/%d", qtask.id, qtask.host, qtask.issue_id)

        return qtask


def load_passwords(filename=PASSWORDS):
    with open(filename) as config_fn:
        return json.load(config_fn)


def load_config(filename=CONFIG):
    with open(filename) as config_fn:
        config_arr = json.load(config_fn)
        config_dict = {}
        for course in config_arr:
            config_dict[course["course_id"]] = course

        return config_dict


def get_auth(passwords, host):
    host_auth = passwords[host]
    return (host_auth["username"], host_auth["password"])


config = load_config()
passwords = load_passwords()
pool = Pool(processes=PROCS)


def put_to_pool(task):
    course_id = task["course_id"]
    course = config[course_id]
    auth = get_auth(passwords, course["host"])
    files = task["files"]

    qtask = QueueTask()
    qtask.host = course["host"]
    qtask.auth = auth
    qtask.course = course
    qtask.task = task["title"]
    qtask.issue_id = task["issue_id"]
    qtask.files = files
    qtask.id = task["event"]["id"]
    qtask.event_timestamp = task["event"]["timestamp"]
    print(qtask)
    pool.apply_async(process_task, args=(qtask,))

#run_cmd = ["ls", "/task_dir/task"]