"""Merged coordinator and weekly reminder runtime regressions."""

from __future__ import annotations

import json
from datetime import date, datetime
from pathlib import Path
from typing import final, override

import pytest

from checkin_cli.customer_schedule import schedule_delivery_ledger
from checkin_cli.weekly_operations_schedule_host_models_r4 import CustomerScheduleTask
from gateway.config import PlatformConfig
from gateway.platforms.nutrition_coaching import NutritionCoachingCoordinator
from gateway.platforms.nutrition_weekly_reminder import TelegramReminderDelivered
from gateway.platforms.nutrition_weekly_reminder_authority import (
    RegisteredWeeklyReminderCustomer,
    WeeklyReminderOwnerError,
)
from gateway.platforms.nutrition_weekly_reminder_owner_factory import (
    WeeklyReminderProductionInput,
)
from gateway.platforms.telegram import TelegramAdapter
from gateway.platforms.telegram_weekly_reminder import send_weekly_operations_task
from tests.gateway._nutrition_weekly_reminder_support import (
    CANDIDATE,
    KST,
    FakeTelegramHost,
    ReminderContextSource,
    ReminderOwnerCoordinator,
    reminder_owner_fixture,
    registry_payload,
)


@pytest.mark.asyncio
async def test_registered_owner_drives_reminder_and_cutoff(tmp_path: Path) -> None:
    fixture = reminder_owner_fixture(tmp_path)
    coordinator = ReminderOwnerCoordinator(fixture.owner, fixture.registry)
    host = FakeTelegramHost()
    reminder = CustomerScheduleTask("client_001", "reminder", date(2026, 8, 17))
    cutoff = CustomerScheduleTask("client_001", "cutoff", date(2026, 8, 17))

    first = await send_weekly_operations_task(
        host, coordinator, reminder, local_now=datetime(2026, 8, 17, 20, tzinfo=KST)
    )
    second = await send_weekly_operations_task(
        host, coordinator, cutoff, local_now=datetime(2026, 8, 17, 23, tzinfo=KST)
    )

    assert first is None and second is None
    assert host.calls == 1
    assert fixture.store.read()[-1].state == "missed"
    fixture.owner.close()


@pytest.mark.asyncio
async def test_registry_route_drift_twice_is_zero_call_one_incident(
    tmp_path: Path,
) -> None:
    context = ReminderContextSource()
    fixture = reminder_owner_fixture(tmp_path, context)
    coordinator = ReminderOwnerCoordinator(fixture.owner, fixture.registry)
    changed_path = tmp_path / "changed-registry.json"
    _ = changed_path.write_text(
        json.dumps(
            registry_payload(chat_id="unauthorized-chat", topic_id="wrong-topic")
        ),
        encoding="utf-8",
    )
    from checkin_cli.customer_coaching import load_customer_registry

    changed_registry = load_customer_registry(changed_path, tmp_path)
    context.after_snapshot = lambda: setattr(coordinator, "registry", changed_registry)
    host = FakeTelegramHost()
    task = CustomerScheduleTask("client_001", "reminder", date(2026, 8, 17))

    first = await send_weekly_operations_task(
        host, coordinator, task, local_now=datetime(2026, 8, 17, 20, tzinfo=KST)
    )
    with pytest.raises(WeeklyReminderOwnerError, match="route drift"):
        _ = await send_weekly_operations_task(
            host, coordinator, task, local_now=datetime(2026, 8, 17, 20, tzinfo=KST)
        )

    receipts = schedule_delivery_ledger(tmp_path)
    assert first == "client_001:2026-08-17:reminder"
    assert host.calls == 0
    assert len(receipts) == 1 and receipts[0].state == "abandoned"
    fixture.owner.close()


@final
class MergedTelegramAdapter(TelegramAdapter):
    def __init__(
        self,
        config: PlatformConfig,
        customer: RegisteredWeeklyReminderCustomer,
    ) -> None:
        super().__init__(config, weekly_reminder_customers=(customer,))
        self.calls: int = 0
        self._task26_candidate_digest = CANDIDATE

    @override
    async def send_weekly_reminder(
        self, chat_id: str, topic_id: str | None, text: str
    ) -> TelegramReminderDelivered:
        assert (chat_id, topic_id) == ("customer-chat", "customer-topic")
        assert text
        self.calls += 1
        return TelegramReminderDelivered("provider-1", "message-1")


@pytest.mark.asyncio
async def test_merged_coordinator_constructs_reminder_owner_beside_todo8(
    tmp_path: Path,
) -> None:
    fixture = reminder_owner_fixture(tmp_path)
    production = WeeklyReminderProductionInput(
        fixture.extra,
        CANDIDATE,
        fixture.registry,
        fixture.registry_path,
        (fixture.customer,),
    )
    coordinator = NutritionCoachingCoordinator(
        tmp_path,
        fixture.registry,
        task26_candidate_digest=CANDIDATE,
        weekly_reminder_owner_input=production,
    )
    adapter = MergedTelegramAdapter(
        PlatformConfig(enabled=True, token="fixture", extra=fixture.extra),
        fixture.customer,
    )
    task = CustomerScheduleTask("client_001", "reminder", date(2026, 8, 17))
    result = await send_weekly_operations_task(
        adapter, coordinator, task,
        local_now=datetime(2026, 8, 17, 20, tzinfo=KST),
    )

    assert result is None
    assert adapter.calls == 1
    assert coordinator.weekly_reminder_authority_owner is not None
    assert callable(coordinator.create_grounded_weekly_owner_draft)
    assert callable(coordinator.weekly_owner_storage_authority)
    coordinator.weekly_reminder_authority_owner.close()


def test_merged_coordinator_off_remains_typed_and_inert(tmp_path: Path) -> None:
    fixture = reminder_owner_fixture(tmp_path)
    production = WeeklyReminderProductionInput(
        {}, None, fixture.registry, fixture.registry_path, ()
    )
    coordinator = NutritionCoachingCoordinator(
        tmp_path,
        fixture.registry,
        registry_path=fixture.registry_path,
        weekly_reminder_owner_input=production,
    )
    host = FakeTelegramHost()

    with pytest.raises(WeeklyReminderOwnerError, match="unavailable"):
        _ = coordinator.weekly_reminder_authority_owner
    assert host.calls == 0
    fixture.owner.close()


@pytest.mark.parametrize("candidate", (CANDIDATE, "f" * 64))
def test_merged_coordinator_rejects_missing_or_stale_owner_zero_call(
    tmp_path: Path, candidate: str
) -> None:
    fixture = reminder_owner_fixture(tmp_path)
    customers = () if candidate == CANDIDATE else (fixture.customer,)
    production = WeeklyReminderProductionInput(
        fixture.extra,
        candidate,
        fixture.registry,
        fixture.registry_path,
        customers,
    )
    host = FakeTelegramHost()

    with pytest.raises(
        WeeklyReminderOwnerError,
        match="capability is unavailable|candidate authority disagrees",
    ):
        _ = NutritionCoachingCoordinator(
            tmp_path,
            fixture.registry,
            registry_path=fixture.registry_path,
            task26_candidate_digest=CANDIDATE,
            weekly_reminder_owner_input=production,
        )
    assert host.calls == 0
    fixture.owner.close()
