import distutils.util
import os
import subprocess
import time
import urllib
import urlparse

from lib_python import steps, execution, logger, variables
from libcrashtest.cap.File import download_file

__HTTP_OK = 200

__CAP_SERVER_BASE_URL = "http://localhost:8080"
__CAP_CONTROLLER_NAME_FILE = "file?guid={0}"
__CAP_CONTROLLER_NAME_DELETE = "delete?guid={0}"
__CAP_CONTROLLER_NAME_FILES = "files"
__CAP_CONTROLLER_NAME_UPLOADING = "uploading"
__CAP_CONTROLLER_NAME_ENABLE_SERVER = "enable-server"
__CAP_CONTROLLER_NAME_DISABLE_SERVER = "disable-server"


def start_cap_server():
    # noinspection SpellCheckingInspection
    cap_server_path = os.path.join(os.environ["USERPROFILE"], "capserver", "capserver.jar")
    logger.info("CAP Server Path: {0}".format(cap_server_path))
    subprocess.Popen(["java", "-jar", cap_server_path], creationflags=subprocess.CREATE_NEW_CONSOLE)

    execution.passed()


steps.new_step("Start CAP Server", start_cap_server)


def list_uploaded_guids():
    request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_FILES))
    response = request.read()

    if len(response) > 0:
        variables.guids = response.split('\n')
        variables.last_guid = variables.guids[len(variables.guids) - 1]  # store the last guid in a global variable
    else:
        variables.guids = []
        variables.last_guid = None

    execution.passed()


steps.new_step("CAP - List uploaded GUIDs", list_uploaded_guids)


def download_file_from_cap(params):
    location = params["location"]
    guid = variables.last_guid

    if guid is None:
        execution.error("Unable to download the last crash file: GUID is None.")

    url = urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_FILE.format(guid))
    logger.info("Downloading file from: {0}".format(url))

    if not download_file(url, location):
        execution.error("Unable to download file at: {0}".format(urlparse.urljoin(url)))

    execution.passed()


steps.new_step("CAP - Download latest crash file from CAP mock server to location: {location}", download_file_from_cap)


def wait_until_cap_starts_to_process_upload():
    timeout = 120  # seconds
    start = time.time()

    upload_started = False

    while time.time() - start < timeout and not upload_started:
        logger.debug("Contacting CAP server for current uploading status.")
        request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_UPLOADING))
        response = request.read()
        upload_started = distutils.util.strtobool(response)
        time.sleep(5)  # wait for five seconds

    if not upload_started:
        execution.error("Uploading did not finish in {0} seconds. Aborting.".format(timeout))

    execution.passed()


steps.new_step("CAP - Wait until CAP starts to process an upload", wait_until_cap_starts_to_process_upload)


def wait_until_uploading_has_finished():
    timeout = 10 * 60  # ten minutes in seconds
    start = time.time()

    uploading_finished = False

    while time.time() - start < timeout and not uploading_finished:
        logger.debug("Contacting CAP server for current uploading status.")
        request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_UPLOADING))
        response = request.read()
        uploading_finished = not distutils.util.strtobool(response)
        time.sleep(5)  # wait for five seconds

    if not uploading_finished:
        execution.error("Uploading did not finish in {0} seconds. Aborting.".format(timeout))

    execution.passed()


steps.new_step("CAP - Wait until uploading has finished", wait_until_uploading_has_finished)


def check_that_cap_is_not_processing_upload():
    start = time.time()

    testing_period = 15  # seconds

    while time.time() - start < testing_period:
        request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_UPLOADING))
        response = request.read()

        if distutils.util.strtobool(response):
            execution.error("CAP server has reported that it's processing an upload")

        time.sleep(5)  # sleep for 5 seconds

    execution.passed()


steps.new_step("CAP - Check that CAP is not processing an upload", check_that_cap_is_not_processing_upload)


def delete_last_crash_report_from_cap():
    request = urllib.urlopen(
        urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_DELETE.format(variables.last_guid))
    )

    response_http_code = request.getcode()

    if response_http_code != __HTTP_OK:
        execution.error(
            "CAP mock returned invalid response code: {0}, response: {1}".format(response_http_code, request.read())
        )

    execution.passed()


steps.new_step("CAP - Delete last crash report from CAP", delete_last_crash_report_from_cap)


def check_that_last_reported_guid_is_empty():
    if variables.last_guid is not None:
        execution.error("Last reported  GUID is {0} and should be None instead!".format(variables.last_guid))

    execution.passed()


steps.new_step("CAP - Check there are no reported crash reports", check_that_last_reported_guid_is_empty)


def enable_cap_server():
    request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_ENABLE_SERVER))

    response_http_code = request.getcode()

    if response_http_code != __HTTP_OK:
        execution.error(
            "CAP mock returned invalid response code: {0}, response: {1}".format(response_http_code, request.read())
        )

    execution.passed()


steps.new_step("CAP - Enable CAP server", enable_cap_server)


def disable_cap_server():
    request = urllib.urlopen(urlparse.urljoin(__CAP_SERVER_BASE_URL, __CAP_CONTROLLER_NAME_DISABLE_SERVER))

    response_http_code = request.getcode()

    if response_http_code != __HTTP_OK:
        execution.error(
            "CAP mock returned invalid response code: {0}, response: {1}".format(response_http_code, request.read())
        )

    execution.passed()


steps.new_step("CAP - Disable CAP server", disable_cap_server)
