import threading
from datetime import timedelta

from opentelemetry import trace
from model import EventRepositoryFactory
from timeutil import (
    Clock,
    Sleeper,
)

tracer = trace.get_tracer(__name__)


class MaintenanceService(object):
    def __init__(
        self,
        event_repository_factory: EventRepositoryFactory,
        sleeper: Sleeper,
        clock: Clock,
        maintenance_interval: int,
        acked_events_ttl: int,
        abandoned_events_ttl: int,
    ):
        self.event_repository_factory = event_repository_factory
        self.sleeper = sleeper
        self.clock = clock
        self.maintenance_interval = float(maintenance_interval / 1000)
        self.acked_events_ttl = acked_events_ttl
        self.abandoned_events_ttl = abandoned_events_ttl

        self.thread = None
        self.running = False

    def start(self):
        if self.thread is None:
            self.thread = threading.Thread(target=self._cleanup, args=[self.maintenance_interval])
            self.thread.daemon = True
            self.running = True
            self.thread.start()

    def stop(self):
        self.running = False

    def cleanup(self):
        with tracer.start_span(name="MaintenanceCleanup") as span:
            span.set_attribute(
                key="startAt",
                value=self.clock.utc_now().isoformat(),
            )
            with self.event_repository_factory.build() as event_repository:
                abandoned_date_limit = self.clock.utc_now() - timedelta(days=self.abandoned_events_ttl)
                event_repository.cleanup_abandoned_events(min_abandoned_date=abandoned_date_limit)

                acked_date_limit = self.clock.utc_now() - timedelta(days=self.acked_events_ttl)
                event_repository.cleanup_acked_events(min_acked_date=acked_date_limit)
            span.set_attribute(
                key="finishAt",
                value=self.clock.utc_now().isoformat(),
            )

    def _cleanup(self, interval):
        while self.running:
            self.cleanup()
            self.sleeper.sleep(interval)
