import sys
from threading import Thread
from time import sleep

import click

import sdccli.usecases.scanning.vulnerability as use_case
from sdccli.cli.scanning.vulnerability.bundle import bundle


@click.group(name='vulnerability', short_help='Vulnerability operations')
def vulnerability():
    pass


@vulnerability.command(name='report', short_help="Downloads a vulnerability report in CSV format")
@click.option("--runtime", help="Generate vulnerability report for runtime images only", type=bool, is_flag=True)
@click.option("--os",
              help="Generates a vulnerability report for OS images only. By default generates for OS and NonOS.",
              type=bool,
              is_flag=True)
@click.option("--non-os", help="Generates a vulnerability report for NonOS images (pip, npm, java, ...) only. "
                               "By default generates for OS and NonOS.", type=bool, is_flag=True)
@click.argument('report_path', nargs=1)
@click.pass_obj
def report(cnf, runtime, os, non_os, report_path):
    """
    Downloads a vulnerability report at the given path.
    """
    if cnf.json:
        print("Json format is not supported for this method")
        sys.exit(1)

    # Prints a message after 2 minutes waiting for the generation of the report
    def wait_time():
        sleep(120)
        print("It looks like the report is taking more time than expected.")
        print("This may be due to the high amount of images in your system.")

    try:
        with open(report_path, "w") as f:
            print(f"Downloading report at {f.name}.")
            Thread(target=wait_time, daemon=True).run()
            use_case.download_vulnerability_report(cnf.sdscanning, runtime, os, non_os, f)
            print("Report downloaded")
    except Exception as ex:
        if "504" in str(ex):
            print("Timed out while waiting for the CVE report to be downloaded. "
                  "Max time limit is 3 minutes to retrieve either OS or NonOS reports.")
            if not os and not non_os:
                print("You can try executing again with --os or --non-os options for a fewer number of images.")
            if not runtime:
                print("You can also try using the --runtime options which only downloads a report or running images.")
            sys.exit(1)
        print(ex)
        sys.exit(1)


@vulnerability.command(name='get_info', short_help="Retrieves information about a vulnerability")
@click.argument('cve', nargs=1)
@click.pass_obj
def add(cnf, cve):
    """
    CVE: The CVE from which more info should be retrieved.
    """
    try:
        res = use_case.get_vulnerability_details(cnf.sdscanning, cve)
        cnf.formatter.format(res, "vulnerabilityDetails")
    except Exception as ex:
        print(ex)


@vulnerability.command(name='add_exception', short_help="Adds a vulnerability exception to a bundle")
@click.argument('bundleid', nargs=1)
@click.argument('cve', nargs=1)
@click.option('--notes', nargs=1, help="Notes for the vulnerability exception")
@click.option('--expiration-date', nargs=1, help="Expiration date in Unix time format")
@click.pass_obj
def add(cnf, bundleid, cve, notes=None, expiration_date=None):
    """
    BUNDLEID: The Bundle ID to add the CVE exception to.
    CVE: The CVE that should be added
    """
    try:
        res = use_case.add_vulnerability_exception(cnf.sdscanning, bundleid, cve, notes, expiration_date)
        cnf.formatter.format(res, "vulnerabilityExceptionAdded")

    except Exception as ex:
        print(ex)


@vulnerability.command(name='del_exception', short_help="Deletes a vulnerability exception from a bundle")
@click.argument('bundleid', nargs=1)
@click.argument('cve', nargs=1)
@click.pass_obj
def delete(cnf, bundleid, cve):
    """
    BUNDLEID: The Bundle ID to remove the CVE exception from.
    CVE: The CVE that should be deleted
    """
    try:
        res = use_case.delete_vulnerability_exception(cnf.sdscanning, bundleid, cve)
        print("Succeed")

    except Exception as ex:
        print(ex)


vulnerability.add_command(bundle)
