import logging
from datetime import datetime
from threading import Event, Thread

import pytz


class CleanupTimer:
    """Provides a timed cleanup of the spot list."""

    def __init__(self, spots, alerts, web_server, cleanup_interval):
        """Constructor"""

        self._spots = spots
        self._alerts = alerts
        self._web_server = web_server
        self._cleanup_interval = cleanup_interval
        self.last_cleanup_time = datetime.min.replace(tzinfo=pytz.UTC)
        self.status = "Starting"
        self._thread = None
        self._stop_event = Event()

    def start(self):
        """Start the cleanup timer"""

        self._thread = Thread(target=self._run, daemon=True)
        self._thread.start()

    def stop(self):
        """Stop any threads and prepare for application shutdown"""

        self._stop_event.set()

    def _run(self):
        while not self._stop_event.wait(timeout=self._cleanup_interval):
            self._cleanup()

    def _cleanup(self):
        """Perform cleanup and reschedule next timer"""

        try:
            # Perform cleanup via letting the data expire
            self._spots.expire()
            self._alerts.expire()

            # Explicitly clean up any spots and alerts that have expired
            for i in list(self._spots.iterkeys()):
                try:
                    spot = self._spots[i]
                    if spot.expired():
                        self._spots.delete(i)
                except KeyError:
                    # Must have already been deleted, OK with that
                    pass
            for i in list(self._alerts.iterkeys()):
                try:
                    alert = self._alerts[i]
                    if alert.expired():
                        self._alerts.delete(i)
                except KeyError:
                    # Must have already been deleted, OK with that
                    pass

            # Clean up web server SSE spot/alert queues
            self._web_server.clean_up_sse_queues()

            self.status = "OK"
            self.last_cleanup_time = datetime.now(pytz.UTC)

        except Exception:
            self.status = "Error"
            logging.exception("Exception in Cleanup thread")
            self._stop_event.wait(timeout=1)
