"""Behavioral RED/GREEN controls for Todo11 r3 production boundaries."""

from pathlib import Path



import pytest

from gateway.config import PlatformConfig
from gateway.platforms.nutrition_coaching import IncomingAddress
from gateway.platforms.nutrition_weekly_dispatcher_transport import (
    RevalidatingTopic59Transport,
)

from gateway.platforms.nutrition_weekly_operations_publication_contract import (
    Topic59ProviderDelivered,
    Topic59ProviderFailure,
    Topic59ProviderKnownFailure,
    Topic59ProviderOutcome,
    Topic59ProviderUnknown,
)
from scripts.nutricoach_v140_authority_fixture import CANDIDATE
from scripts.nutricoach_v140_fake_telegram_updates import FakeCallbackQuery
from scripts.nutricoach_v140_fake_telegram import (
    FakeTelegramEngine,
    ProviderMode,
    fake_bot,
)

from scripts.nutricoach_v140_owner_fixture import (
    create_owner_coordinator,
    create_weekly_owner_draft,
    owner_platform_config,
)
from scripts.nutricoach_v140_telegram_facade import (
    DisposableOwnerTelegramAdapter,
    DisposableWeeklyTelegramAdapter,
)

from scripts.nutricoach_v140_topic59_fixture import create_topic59_fixture


RAW_SENTINELS = (
    "• 체중: 70",
    "• 칼로리: 2300",
    "• 단백질·탄수화물·지방(기존 입력 순서): 150 280 65",
    "• 식사(끼니별 Meal 기록): planned meals",
    "• 수분: 2.5",
    "• 수면 시간: 7",
    "• 수면 질: 4",
    "• 소화·배변: 특이 불편 없음",
    "• 컨디션: 4",
    "• 식욕·스트레스: appetite stable",
    "• 운동: lower body",
)


@pytest.fixture
def anyio_backend() -> str:
    return "asyncio"


@pytest.mark.anyio
@pytest.mark.parametrize(
    ("mode", "expected"),
    (
        (ProviderMode.KNOWN_FAILURE, Topic59ProviderKnownFailure(
            Topic59ProviderFailure.REJECTED,
        )),
        (ProviderMode.TIMEOUT, Topic59ProviderUnknown(
            Topic59ProviderFailure.TIMEOUT,
        )),
        (ProviderMode.UNKNOWN, Topic59ProviderUnknown(
            Topic59ProviderFailure.CONNECTION_LOST,
        )),
    ),
)
async def test_topic59_edit_classifier_is_shared_with_production_transport(
    tmp_path: Path,
    mode: ProviderMode,
    expected: Topic59ProviderOutcome,
) -> None:
    fixture = create_topic59_fixture(tmp_path / "authority")
    engine = FakeTelegramEngine()
    adapter = DisposableWeeklyTelegramAdapter(
        PlatformConfig(enabled=True, token="disabled", extra=fixture.authority.extra),
        fake_bot(engine), CANDIDATE,
    )
    sent = await adapter.send_topic59("200", "59", "first")
    assert isinstance(sent, Topic59ProviderDelivered)
    engine.set_mode(mode)
    transport = RevalidatingTopic59Transport(adapter, lambda: True)
    outcome = await transport.edit(
        chat_id="200", topic_id="59", message_id=sent.message_id, text="later",
    )
    assert outcome == expected
    assert engine.attempts == 2


@pytest.mark.anyio
@pytest.mark.parametrize(
    ("user_id", "chat_id", "topic_id", "chat_type"),
    (
        ("101", "100", None, "private"),
        ("100", "101", None, "private"),
        ("100", "100", "59", "supergroup"),
    ),
)
async def test_wrong_owner_route_is_denied_before_any_callback_io(
    tmp_path: Path,
    user_id: str,
    chat_id: str,
    topic_id: str | None,
    chat_type: str,
) -> None:
    coordinator = create_owner_coordinator(tmp_path / "owner")
    created = create_weekly_owner_draft(tmp_path / "weekly", coordinator)
    assert created.draft is not None
    engine = FakeTelegramEngine()
    bot = fake_bot(engine)
    adapter = DisposableOwnerTelegramAdapter(
        owner_platform_config(), bot, coordinator,
    )
    assert created.draft.draft_id is not None
    message_id = await adapter.publish_owner_card(
        IncomingAddress("100", "100", "0"),
        coordinator.draft(created.draft.draft_id, coordinator.owner),
    )
    callback = engine.callback("100", message_id, "e")
    engine.actions.clear()
    engine.attempts = 0
    query = FakeCallbackQuery(
        bot, engine, data=callback, user_id=user_id, chat_id=chat_id,
        message_id=message_id, topic_id=topic_id, chat_type=chat_type,
        source_chat_id="100",
    )
    denial = await adapter.handle_owner_callback(query)
    assert denial is not None
    assert engine.actions == []
    assert engine.attempts == 0
    assert query.answers == []


@pytest.mark.anyio
async def test_weekly_owner_card_raw_capture_excludes_every_daily_sentinel(
    tmp_path: Path,
) -> None:
    coordinator = create_owner_coordinator(tmp_path / "owner")
    created = create_weekly_owner_draft(tmp_path / "weekly", coordinator)
    assert created.draft is not None
    engine = FakeTelegramEngine()
    adapter = DisposableOwnerTelegramAdapter(
        owner_platform_config(), fake_bot(engine), coordinator,
    )
    assert created.draft.draft_id is not None
    action = coordinator.draft(created.draft.draft_id, coordinator.owner)
    legacy_daily_projection = adapter.daily_privacy_regression_control(action)
    assert all(sentinel in legacy_daily_projection for sentinel in RAW_SENTINELS)
    _ = await adapter.publish_owner_card(
        IncomingAddress("100", "100", "0"), action,
    )
    captured = "\n".join(item.text for item in engine.captured_texts)
    assert all(sentinel.casefold() not in captured.casefold() for sentinel in RAW_SENTINELS)