# Copyright (C) 2026 NPO NT
# SPDX-License-Identifier: AGPL-3.0-only

from __future__ import annotations

from dataclasses import dataclass
from typing import Callable, Protocol


class CancelSignal(Protocol):
    def is_set(self) -> bool: ...


class OperationCancelled(RuntimeError):
    """Raised when the user cancels a local operation."""


@dataclass(frozen=True, slots=True)
class ProgressUpdate:
    stage: str
    current: int = 0
    total: int = 0


ProgressCallback = Callable[[ProgressUpdate], None]


def ensure_not_cancelled(cancel_signal: CancelSignal | None) -> None:
    if cancel_signal is not None and cancel_signal.is_set():
        raise OperationCancelled("Операция отменена пользователем")


def report_progress(
    callback: ProgressCallback | None,
    stage: str,
    current: int = 0,
    total: int = 0,
) -> None:
    if callback is not None:
        callback(ProgressUpdate(stage=stage, current=current, total=total))
