"""线程安全的取消令牌，用于 ETL 管道的优雅中断。"""

from __future__ import annotations

import threading


class CancellationToken:
    """线程安全的取消令牌，封装 threading.Event。

    支持手动取消和超时自动取消两种模式。
    取消操作不可逆——一旦 cancel() 被调用，is_cancelled 永远为 True。
    """

    def __init__(self, timeout: float | None = None):
        """初始化取消令牌。

        Args:
            timeout: 超时秒数。传入正数时启动守护定时器，
                     到期后自动调用 cancel()。None 或 <=0 不启动定时器。
        """
        self._event = threading.Event()
        self._timer: threading.Timer | None = None
        if timeout is not None and timeout > 0:
            self._timer = threading.Timer(timeout, self.cancel)
            self._timer.daemon = True
            self._timer.start()

    def cancel(self) -> None:
        """发出取消信号（幂等，可多次调用）。"""
        self._event.set()

    @property
    def is_cancelled(self) -> bool:
        """当前是否已取消。"""
        return self._event.is_set()

    @property
    def event(self) -> threading.Event:
        """底层 Event 对象，供 RateLimiter 等组件轮询使用。"""
        return self._event

    def dispose(self) -> None:
        """清理超时定时器，防止资源泄漏。

        管道结束后应主动调用；即使不调用，守护线程也会随主进程退出。
        """
        if self._timer is not None:
            self._timer.cancel()
            self._timer = None
