from __future__ import with_statement

import itertools
import logging
import threading
import traceback

from datetime import datetime
from json import dumps

from .fileprocessing import (
    filter_out_info_files,
    group_files_by_pivot_most_recent_first,
    mark_as_processed,
)


WEBCONNECTOR_EXT = ".webconnector"
INDEXER_EXT = ".indexer"
CRASHLOG_EXT = ".crashlog"
SWAPPER_EXT = ".swapper"
PUSH2_EXT = ".push2"

logger = logging.getLogger(__name__)


def time_delta_ms(time_delta):
    return time_delta.seconds * 1000 + (time_delta.microseconds / 1.0e3)


# event names for the usage reporting


class EventTypes(object):
    START = "start"
    END = "end"
    EXCEPTION = "exception"
    CHECK_FOR_UPDATES = "check_for_updates"
    NO_UPDATES_AVAILABLE = "no_updates_available"
    UPDATE_FOUND = "update_found"
    UPLOAD_EVENT_LOGS = "upload_event_logs"
    WAITING_FOR_LIVE = "waiting_for_live"
    LIVE_TERMINATED = "live_terminated"
    OTHER_LIVE_RUNNING = "other_live_running"
    INVOKING_SWAPPER = "invoking_swapper"
    RETRIEVE_DELTA = "retrieve_delta"
    RETRIEVED_DELTA = "retrieved_delta"
    PREPARE = "prepare"
    COPY_INSTALL = "copy_installation"
    COPIED_INSTALL = "copied_installation"
    UPDATE_COPY = "update_copy"
    UPDATED_COPY = "updated_copy"
    NO_INTERNET_CONNECTION = "no_internet_connection"
    CRASH_DETECTION_FILE_FOUND = "crash_detection_file_found"
    OLD_INSTALLATION_FOUND = "old_installation_found"
    FAILED_TO_DELETE_OLD_INSTALLATION = "failed_to_delete_old_installation"
    WC_INTERRUPTED = "wc_interrupted_by_early_live_termination"
    CLEANUP_EVENT_LOGS = "cleanup_event_logs"
    UPLOAD_INFO = "upload_info"


class UsageReporter(object):
    def __init__(self, outf):
        if outf is None:

            class outf(object):
                @classmethod
                def write(cls, *args):
                    pass

                @classmethod
                def close(cls):
                    pass

        self.outf = outf
        self.lock = threading.Lock()

    def log(self, event, **params):
        now = datetime.utcnow()
        prefix = now.strftime("%Y-%m-%dT%H:%M:%S") + (".%06i=" % now.microsecond)

        params_suffix = ""
        if params:
            params_suffix = " %s" % dumps(params)

        with self.lock:
            self.outf.write("%s%s%s\n" % (prefix, event, params_suffix))

    def __enter__(self):
        pass

    def __exit__(self, e_type, e_value, e_trace):
        try:
            if e_type is not None and e_type is not SystemExit:
                lines = traceback.format_exception(e_type, e_value, e_trace)
                self.log(EventTypes.EXCEPTION, stacktrace="\n".join(lines))
        finally:
            self.outf.close()


def clean_directory(basedir, keep_latest=100):
    logger.debug("clean_directory %s", str(basedir))

    for group in itertools.islice(
        group_files_by_pivot_most_recent_first(basedir, select_processed=True),
        keep_latest,
        None,
    ):
        for f in group:
            logger.debug("Trying to remove %r", f)
            f.remove()


def upload_event_logs(connector, base, usage_reporter):
    logger.debug("upload_event_logs from %s", str(base))
    logger.debug(connector)
    for group in group_files_by_pivot_most_recent_first(base):
        pivot = group.next()
        try:
            logger.debug("trying to upload %s", str(pivot))
            with pivot.open("r") as inf:
                content = inf.read()

            mark_as_processed(pivot)

            run_id = connector.upload_event_log(content)
            usage_reporter.log("uploaded_run", run_id=run_id)

            for log in filter_out_info_files(group):
                kind = log.splitext()[1][1:]
                logger.debug("Found additional log, uploading")
                with log.open("rb") as inf:
                    connector.upload_log(run_id, kind, inf.read())
                    usage_reporter.log("uploaded_log", run_id=run_id, kind=kind)

        except:  # pragma: no cover
            logger.debug("Exception during handling of %s.", str(pivot))
