#!/usr/bin/env python3

import os
import argparse
import webbrowser
import threading
from glob import glob
import time
from dgenies.config_reader import AppConfigReader
from dgenies.bin.clean_jobs import parse_data_folders, parse_database, parse_upload_folders
import requests
from requests.exceptions import ConnectionError

runned = False

config = AppConfigReader()


def parse_args():
    parser = argparse.ArgumentParser(description="Manage dgenies application")
    subparsers = parser.add_subparsers(dest="subparser_name")

    # Run the app:
    run = subparsers.add_parser("run", help="Run the application")
    run.add_argument("-m", "--mode", type=str, choices=["standalone", "webserver"], default="standalone",
                            help="Mode into run the application")
    run.add_argument("-d", "--debug", help="Run in debug mode", type=bool, const=True, nargs="?", required=False,
                     default=False)
    run.add_argument("-o", "--host", help="Host into run the application", type=str, required=False,
                     default="127.0.0.1")
    run.add_argument("-p", "--port", help="Port into run the application", type=int, required=False, default=5000)
    run.add_argument("--no-crons", help="Do not run crons (for debug only, ignored for standalone mode)", type=bool,
                     const=True, nargs="?", required=False, default=False)
    run.add_argument("--no-browser", type=bool, const=True, nargs="?", required=False, default=False,
                     help="Do not start the browser (Start of browser is always disabled in debug mode)")

    # Clear data or jobs:
    clear = subparsers.add_parser("clear", help="Clear data")
    clear.add_argument("-c", "--crons", help="Clear crons", type=bool, const=True, nargs="?", required=False,
                       default=False)
    clear.add_argument("-l", "--logs", help="Clear logs", type=bool, const=True, nargs="?", required=False,
                       default=False)
    clear.add_argument("-j", "--jobs", help="Clear jobs", type=bool, const=True, nargs="?", required=False,
                       default=False)
    clear.add_argument("-m", "--max-age", help="Max age for job to delete (0 for all)", type=int, required=False,
                       default=0)
    clear.add_argument("-w", "--web", help="Add this option with -j option, if you use the webserver mode", type=bool,
                     const=True, nargs="?", required=False, default=False)

    # Gallery:
    gallery = subparsers.add_parser("gallery", help="Manage gallery")
    subparsers_gallery = gallery.add_subparsers()

    # Gallery add:
    gallery_add = subparsers_gallery.add_parser("add", help="Add new job to the gallery")
    gallery_add.set_defaults(which="add")
    gallery_add.add_argument("-i", "--id-job", type=str, required=True,
                             help="Id (name) of the job to add to the gallery")
    gallery_add.add_argument("-n", "--name", type=str, required=True, help="Name to show in the gallery for the job")
    gallery_add.add_argument("-q", "--query", type=str, required=True, help="Name of the query")
    gallery_add.add_argument("-t", "--target", type=str, required=True, help="Name of the target")
    gallery_add.add_argument("-p", "--pict", type=str, required=True, help="Name of the file that illustrate the job")

    # Gallery del:
    gallery_del = subparsers_gallery.add_parser("del", help="Delete a job from the gallery")
    gallery_del.set_defaults(which="del")
    gallery_del.add_argument("-i", "--id-job", type=str, required=False,
                             help="Id (name) of the job to delete from the gallery")
    gallery_del.add_argument("-n", "--name", type=str, required=False,
                             help="Name of the job shown in the gallery")
    gallery_del.add_argument("--remove-pict", help="Clear crons", type=bool, const=True, nargs="?", required=False,
                       default=False)

    args = parser.parse_args()

    if args.subparser_name == "run":
        return "run", [args.mode, args.debug, args.host, args.port, args.no_crons, args.no_browser]
    if args.subparser_name == "clear":
        if args.crons == False and args.logs == False and args.jobs == False:
            print("Nothing to do.")
            return "clear", None
        return "clear", args
    if args.subparser_name == "gallery":
        return "gallery_" + args.which, args
    else:
        parser.print_help()
        print("\nYou must specify the command to launch")
        return None, None


def start_browser(host, port, app):
    web_url = "http://{0}:{1}".format(host, port)
    status_code = -1
    tries = 0
    while status_code != 200 and tries < 60:
        try:
            status_code = requests.get(web_url).status_code
        except ConnectionError:
            print("pass")
            status_code = 500
        if status_code != 200:
            time.sleep(1)
            tries += 1
    if app.got_first_request:
        print("Starting browser...")
        webbrowser.open(web_url)
    else:
        print("App has not started. Cancel run of browser")


def run(mode="standalone", debug=False, host="127.0.0.1", port=5000, no_crons=False, no_browser=False):
    os.environ['DISABLE_CRONS'] = "True" if no_crons else "False"
    if debug:
        os.environ['LOGS'] = "True"
    from dgenies import launch
    app = launch(mode=mode, debug=debug)
    if not debug and not no_browser:
        thread = threading.Timer(1, start_browser, kwargs={
            "host": host,
            "port": port,
            "app": app
        })
        thread.start()
    app.run(host=host, port=port, debug=debug, threaded=True)


def clear_crons():
    from dgenies.lib.crons import Crons
    crons = Crons(None, True)
    crons.clear()


def clear_logs():
    if hasattr(config, "log_dir"):
        log_files = glob(os.path.join(config.log_dir, "*.log"))
        for file in log_files:
            os.remove(file)

    else:
        print("No log dir defined!")


def clear_jobs(max_data_age=7, web=False):
    upload_folder = config.upload_folder
    app_data = config.app_data
    now = time.time()

    max_age = {
        "uploads": 0,
        "error": 0,
        "data": max_data_age,
        "fasta_sorted": 0
    }

    print("#########################")
    print("# Parsing Upload folder #")
    print("#########################")
    print("")
    parse_upload_folders(
        upload_folder=upload_folder,
        now=now,
        max_age=max_age
    )
    print("")

    if web:
        print("######################")
        print("# Parsing Jobs in DB #")
        print("######################")
        print("")
        gallery_jobs = parse_database(
            app_data=app_data,
            max_age=max_age
        )
        print("")
    else:
        gallery_jobs = []

    print("#######################")
    print("# Parsing Data folder #")
    print("#######################")
    print("")
    parse_data_folders(
        app_data=app_data,
        now=now,
        max_age=max_age,
        gallery_jobs=gallery_jobs
    )
    print("")


def add_to_gallery(id_job, name, picture, query, target):
    from dgenies.database import Gallery, Job
    from peewee import DoesNotExist
    try:
        job = Job.get(id_job=id_job)
    except DoesNotExist:
        print("Error: job \"%s\" does not exists!" % id_job)
        exit(1)
    else:
        pict_file = os.path.join(config.app_data, "gallery", picture)
        if not os.path.exists(pict_file):
            print("Error: file \"%s\" does not exists!" % pict_file)
            exit(1)
        item = Gallery.create(job=job, name=name, picture=picture, query=query, target=target)
        item.save()


def del_from_gallery_by_id(id_job):
    from dgenies.database import Gallery, Job
    items = Gallery.select().join(Job).where(Job.id_job == id_job)
    list_pictures = []
    for item in items:
        list_pictures.append(item.picture)
        item.delete_instance()
    return list_pictures


def del_from_gallery_by_name(name):
    from dgenies.database import Gallery
    items = Gallery.select().where(Gallery.name == name)
    list_pictures = []
    for item in items:
        list_pictures.append(item.picture)
        item.delete_instance()
    return list_pictures


if __name__ == "__main__":
    command, args = parse_args()
    if command == "run":
        run(*args)
    elif command == "clear":
        if args.crons:
            print("Cleaning crons...")
            clear_crons()
        if args.logs:
            print("Cleaning logs...")
            clear_logs()
        if args.jobs:
            print("Cleaning jobs...")
            clear_jobs(args.max_age, args.web)
    elif command == "gallery_add":
        add_to_gallery(args.id_job, args.name, args.pict, args.query, args.target)
    elif command == "gallery_del":
        if args.id_job is None and args.name is None:
            print("Error: please give an id or a name for the job!")
            exit(1)
        if args.id_job is not None:
            pictures = del_from_gallery_by_id(args.id_job)
        else:
            pictures = del_from_gallery_by_name(args.name)
        if args.remove_pict:
            for picture in pictures:
                try:
                    os.remove(os.path.join(config.app_data, "gallery", picture))
                except FileNotFoundError:
                    pass
