"""Todo 5 r2 evaluator and durable authority regressions."""

from __future__ import annotations

from dataclasses import replace
from datetime import date, datetime
from inspect import signature
from pathlib import Path

import pytest

import checkin_cli
from checkin_cli.customer_schedule import reserve_missing_checkin_reminder
from checkin_cli.weekly_operations_schedule_host_models_r4 import (
    ApprovedReminderScheduleEvidence,
    CustomerScheduleError,
    WeeklyOperationsSchedulePolicy,
)
from checkin_cli.weekly_operations_lifecycle import reminder_reservation_authority
from checkin_cli.weekly_reminder_ledger_authority import LedgerReservation, LedgerTransition
from checkin_cli.weekly_reminder_authority import WeeklyReminderRequest
from tests._weekly_operations_lifecycle_support import DAY, KST, fixture_at
from tests.test_customer_schedule import _registry


def test_r2_exposes_sealed_evaluator_and_request_authority() -> None:
    evaluator = signature(checkin_cli.build_due_customer_tasks)
    reservation = signature(reserve_missing_checkin_reminder)

    assert "weekly_operations_policy" in evaluator.parameters
    assert "weekly_authority" in reservation.parameters
    assert tuple(WeeklyReminderRequest.__dataclass_fields__) == ("bound_customer", "kst_day", "now")


@pytest.mark.parametrize(
    ("instant", "kind"),
    (
        (datetime(2026, 7, 20, 19, 59, 59, tzinfo=KST), None),
        (datetime(2026, 7, 20, 20, 0, 0, tzinfo=KST), "reminder"),
        (datetime(2026, 7, 20, 22, 59, 59, tzinfo=KST), "reminder"),
        (datetime(2026, 7, 20, 23, 0, 0, tzinfo=KST), "cutoff"),
    ),
)
def test_existing_evaluator_applies_exact_weekly_boundaries(
    tmp_path: Path, instant: datetime, kind: str | None
) -> None:
    registry = _registry(tmp_path)
    policy = WeeklyOperationsSchedulePolicy(frozenset(("client_001",)))

    tasks = checkin_cli.build_due_customer_tasks(
        registry, instant, weekly_operations_policy=policy
    )

    weekly_kinds = tuple(task.kind for task in tasks if task.kind in {"reminder", "cutoff"})
    assert weekly_kinds == (() if kind is None else (kind,))


def test_legacy_evaluator_is_unchanged_when_weekly_policy_is_absent(tmp_path: Path) -> None:
    registry = _registry(tmp_path)
    day = date(2026, 7, 20)
    evidence = ApprovedReminderScheduleEvidence("6" * 64, "7" * 64)

    tasks = checkin_cli.build_due_customer_tasks(
        registry,
        datetime(2026, 7, 20, 8, 17, tzinfo=KST),
        missing_morning_checkins={"client_001": day},
        reminder_evidence=evidence,
    )

    assert tuple(task.kind for task in tasks) == ("daily", "weekly", "reminder")


def test_weekly_known_failure_rejects_changed_approval_and_config(tmp_path: Path) -> None:
    fixture = fixture_at(tmp_path, datetime(2026, 8, 17, 20, tzinfo=KST))
    bound = fixture.request.bound_customer
    authority = reminder_reservation_authority(bound)
    reservation = LedgerReservation(
        bound.customer_identity_digest, DAY,
        {"chat_id": bound.route_chat_id, "topic_id": bound.route_topic_id},
        bound.runtime_registry_digest, bound.config_digest, bound.authority_digest,
        bound.canonical.sequence, bound.canonical.digest, authority,
    )
    first = bound.ledger.reserve(reservation)
    sending = bound.ledger.transition(LedgerTransition("sending", first, authority=authority))
    failed = bound.ledger.transition(LedgerTransition("known_failure", sending, "known_no_send"))

    with pytest.raises(CustomerScheduleError, match="authority pins conflict|already terminal"):
        _ = bound.ledger.reserve(
            replace(
                reservation,
                config_digest="f" * 64,
                authority_digest="different-approval",
                weekly_authority=replace(authority, authority_digest="f" * 64),
            )
        )
    assert failed.state == "known_failure"
    assert len({row.reservation_id for row in bound.ledger.receipts()}) == 1
    fixture.close()
