"""Immediate mutable-authority fence for one weekly reminder provider call."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from typing import Protocol, final

from checkin_cli.weekly_reminder_authority import BoundWeeklyReminderCustomer

from .nutrition_weekly_operations_authority import WeeklyOperationsRuntimeContext
from .nutrition_weekly_reminder import (
    TelegramReminderDelivered,
    TelegramReminderRejected,
)
from .nutrition_weekly_reminder_authority import (
    WeeklyOperationsTickSnapshot,
    WeeklyReminderOwnerAuthority,
)


class ReminderFenceHost(Protocol):
    async def send_weekly_reminder(
        self, chat_id: str, topic_id: str | None, text: str
    ) -> TelegramReminderDelivered | TelegramReminderRejected: ...

    def weekly_operations_authority_current(
        self, snapshot: WeeklyOperationsTickSnapshot
    ) -> bool: ...


class ReminderFenceCoordinator(Protocol):
    def refresh_live_registry(self) -> bool: ...

    @property
    def weekly_reminder_authority_owner(self) -> WeeklyReminderOwnerAuthority: ...


@dataclass(frozen=True, slots=True)
class ReminderProviderFence:
    host: ReminderFenceHost
    coordinator: ReminderFenceCoordinator
    snapshot: WeeklyOperationsTickSnapshot
    bound: BoundWeeklyReminderCustomer
    now: datetime


@final
class FencedReminderHost:
    def __init__(self, fence: ReminderProviderFence) -> None:
        self._fence = fence

    async def send_weekly_reminder(
        self, chat_id: str, topic_id: str | None, text: str
    ) -> TelegramReminderDelivered | TelegramReminderRejected:
        fence = self._fence
        if not fence.coordinator.refresh_live_registry():
            return TelegramReminderRejected("registry_refresh_failed")
        try:
            owner = fence.coordinator.weekly_reminder_authority_owner
            current = owner.tick_snapshot(
                fence.snapshot.runtime.customer_key, fence.now
            )
            bound = owner.bound_customer(
                fence.snapshot.runtime.customer_key, fence.now
            )
        except RuntimeError:
            return TelegramReminderRejected("authority_changed")
        if not _current(fence, current.runtime, bound, chat_id, topic_id):
            return TelegramReminderRejected("authority_changed")
        return await fence.host.send_weekly_reminder(chat_id, topic_id, text)


def _current(
    fence: ReminderProviderFence,
    runtime: WeeklyOperationsRuntimeContext,
    bound: BoundWeeklyReminderCustomer,
    chat_id: str,
    topic_id: str | None,
) -> bool:
    return (
        fence.host.weekly_operations_authority_current(fence.snapshot)
        and runtime == fence.snapshot.runtime
        and bound.authority_digest == fence.bound.authority_digest
        and chat_id == fence.bound.route_chat_id
        and topic_id == fence.bound.route_topic_id
    )
