from __future__ import annotations

from app.services.runtime_chat import RuntimeChatOperationContext, RuntimeChatService
from app.services.runtime_chat_attempts import RuntimeChatAttemptPermit


class RecordingAttemptObserver:
    def __init__(self, timeline: list[str] | None = None) -> None:
        self.permits = []
        self.completed = []
        self.failures = []
        self.timeline = timeline

    def on_permit(self, event):
        self.permits.append(event)
        if self.timeline is not None:
            self.timeline.append(f"permit:{event.identity.attempt}")
        return None

    def on_completed(self, event) -> None:
        self.completed.append(event)
        if self.timeline is not None:
            self.timeline.append(
                f"completed:{event.identity.attempt}:{event.outcome}"
            )

    def on_observer_failure(self, failure) -> None:
        self.failures.append(failure)


class FailingCompletionObserver(RecordingAttemptObserver):
    def on_completed(self, event) -> None:
        super().on_completed(event)
        raise RuntimeError("completion observer unavailable")


class FailingPermitObserver(RecordingAttemptObserver):
    def on_permit(self, event):
        super().on_permit(event)
        raise RuntimeError("permit observer unavailable")


class DenyingAttemptObserver(RecordingAttemptObserver):
    def on_permit(self, event):
        super().on_permit(event)
        return RuntimeChatAttemptPermit(
            allowed=False,
            reason="tenant quota exhausted",
        )


def build_operation_context() -> RuntimeChatOperationContext:
    return RuntimeChatOperationContext(
        tenant_id="tenant-runtime-chat",
        operation_id="operation-runtime-chat-001",
        run_id="run-runtime-chat-001",
        invocation_seq=7,
        attempt_scope="unit-test-completion",
    )


def patch_single_slot(
    monkeypatch,
    service: RuntimeChatService,
    *,
    provider: str,
    model: str,
) -> None:
    monkeypatch.setattr(
        service,
        "_load_chat_slot",
        lambda slot: {
            "slot": slot,
            "provider": provider,
            "endpoint": "https://example.com/v1",
            "model": model,
            "apiKey": "secret",
        },
    )
