import logging

from datetime import datetime

from .errors import DownloadsNotFinished, WrongChecksum
from .reporting import EventTypes as et
from .reporting import time_delta_ms


logger = logging.getLogger(__name__)


class DownloadTask(object):
    def __init__(self, connector, delta, checksum):
        self.connector = connector
        self.checksum = checksum
        self.delta = delta
        self.in_progress = delta + ".part"
        self.finished = False

    def perform(self, usage_reporter):
        logger.info("Retrieving delta %s", self.delta.basename())
        usage_reporter.log(et.RETRIEVE_DELTA, basename=self.delta.basename())
        start = datetime.now()

        checksum = self.connector.retrieve_delta_into(
            self.delta.basename(), self.in_progress
        )
        if self.checksum != checksum:
            raise WrongChecksum

        # atomic renaming from part to
        # actual delta-file-name
        self.in_progress.move(self.delta)
        self.finished = True

        time_elapsed = time_delta_ms(datetime.now() - start)
        logger.info("Delta retrieved, elapsed time: %dms", time_elapsed)
        usage_reporter.log(et.RETRIEVED_DELTA, elapsed_ms=time_elapsed)


class PrepareAutoUpdateTask(object):
    def __init__(self, connector, from_v, to_v, download_tasks):
        self.connector = connector
        self.from_v = from_v
        self.to_v = to_v
        self.download_tasks = download_tasks

    def perform(self, usage_reporter):
        logger.info("Preparing auto-update tasks")
        usage_reporter.log(et.PREPARE, from_version=self.from_v, to_version=self.to_v)

        if not all(dt.finished for dt in self.download_tasks):
            raise DownloadsNotFinished()

        info = self.connector.load_update_info()

        to_version_info = info["versions"][self.from_v][self.to_v]

        # explicit, because None signifies disabled
        if to_version_info["status"] == "downloading":
            to_version_info["status"] = "available"

        self.connector.save_update_info(info)

        if to_version_info["status"]:
            # this invokes the Ableton Updater and waits for
            # return
            self.connector.prepare_available_auto_update(
                self.from_v, self.to_v, usage_reporter
            )

        if self.connector.pending_update_available():
            info = self.connector.load_update_info()
            to_version_info = info["versions"][self.from_v][self.to_v]

            to_version_info["status"] = "prepared"
            info["prepared_version"] = [self.from_v, self.to_v]

            self.connector.save_update_info(info)
