"""MonitoringPlatform: glue that owns session lifecycle and delegates to collectors."""

import os
import shutil
import time
from datetime import datetime

from feathersdk.utils.feathertypes import *
from feathersdk.utils.logger import warning

from ..steppable_system import SteppableSystem
from .collectors import (
    MotorCommandCollector,
    MotorFeedbackCollector,
    StepTimingCollector,
)

if TYPE_CHECKING:
    from ..motors.motors_manager import MotorsManager

T = TypeVar("T")


class MonitoringPlatform(SteppableSystem):
    """Coordinates monitoring collectors: session dir, start/stop, periodic dump."""

    def __init__(self, motors_manager: "MotorsManager", config: dict = None):
        super().__init__()
        config = config or {}
        self.operating_frequency = 1 / 60
        self.motors_manager = motors_manager
        self._output_dir = config.get("output_dir", "/feathersys/logs/feather_monitoring")
        self._reference_wall_time: float = 0.0
        self._reference_monotonic: float = 0.0
        self._session_dir = os.path.join(self._output_dir, "UNINITIALIZED")
        self._cleanup_done = False

        self._collectors = [
            MotorFeedbackCollector(motors_manager, config),
            MotorCommandCollector(motors_manager, config),
            StepTimingCollector(motors_manager, config),
        ]

    def get_collector(self, cls: Type[T]) -> Optional[T]:
        """Return the first collector that is an instance of cls, or None."""
        return next((c for c in self._collectors if isinstance(c, cls)), None)

    def _dump_to_disk(self) -> None:
        for c in self._collectors:
            c.dump(self._session_dir, self._reference_wall_time, self._reference_monotonic)

    def _cleanup_old_logs(self, max_age_days: int = 7) -> None:
        if not os.path.isdir(self._output_dir):
            return
        cutoff_time = time.time() - (max_age_days * 24 * 3600)
        try:
            for name in os.listdir(self._output_dir):
                if not name.startswith("run_"):
                    continue
                path = os.path.join(self._output_dir, name)
                if not os.path.isdir(path) or os.path.normpath(path) == os.path.normpath(self._session_dir):
                    continue
                try:
                    if os.path.getmtime(path) < cutoff_time:
                        shutil.rmtree(path)
                except (OSError, PermissionError) as e:
                    warning(f"MonitoringPlatform: Log cleanup failed for {path}: {e}")
        except (OSError, PermissionError) as e:
            warning(f"MonitoringPlatform: Log cleanup failed listing output_dir {self._output_dir}: {e}")

    def _step(self) -> None:
        if not self._cleanup_done:
            self._cleanup_old_logs()
            self._cleanup_done = True
        for c in self._collectors:
            c.dump(self._session_dir, self._reference_wall_time, self._reference_monotonic)

    def start(self, is_root_step: bool = False) -> None:
        super().start(is_root_step)
        self._reference_monotonic = time.monotonic()
        self._reference_wall_time = time.time()
        session_name = datetime.fromtimestamp(self._reference_wall_time).strftime("run_%Y-%m-%d_%H-%M-%S")
        self._session_dir = os.path.join(self._output_dir, session_name)
        os.makedirs(self._session_dir, exist_ok=True)
        for c in self._collectors:
            c.start()

    def on_abort(self) -> None:
        for c in self._collectors:
            c.stop()
        for c in self._collectors:
            c.dump(self._session_dir, self._reference_wall_time, self._reference_monotonic)
