from __future__ import annotations

from dataclasses import fields
import importlib.util
import json
from pathlib import Path
import re

import pytest

from gateway.platforms.nutrition_coaching_proposal import (
    CoachReview,
    NutritionTargets,
    coach_review_from_dict,
    coach_review_to_dict,
)
from gateway.platforms.telegram_nutrition_onboarding import (
    NUTRITION_ONBOARDING_API_VERSION,
    decode_callback,
    encode_callback,
)
from gateway.platforms.telegram_nutrition_onboarding_copy import card


def test_callback_v2_and_historical_non1_is_rejected() -> None:
    assert NUTRITION_ONBOARDING_API_VERSION == "2.0"
    value = encode_callback(action="owner_ok", generation=3, session_id="sid")
    assert value.startswith("non2:")
    assert decode_callback(value).action == "owner_ok"
    with pytest.raises(ValueError, match="historical"):
        decode_callback(value.replace("non2:", "non1:", 1))


def test_owner_review_card_has_exact_v1_authority() -> None:
    status = type("Status", (), {"state": type("State", (), {"value": "owner_review"})()})()
    text, action, role = card(status)
    assert role == "owner"
    assert action == "owner_ok"
    assert "트레이너" not in text


def test_legacy_runtime_modules_are_absent() -> None:
    modules = (
        "gateway.platforms.telegram_room_bootstrap",
        "gateway.platforms.telegram_pending_marker_intake",
        "gateway.platforms.telegram_nutrition_onboarding_task23_supersession",
        "gateway.platforms.task23_portable_coach_successor",
    )

    assert all(importlib.util.find_spec(module) is None for module in modules)


def test_owner_review_safety_notes_are_serialized_without_trainer_handoff_data() -> None:
    review = CoachReview(
        schema_version="nutrition-coach-review-v3",
        current_targets=NutritionTargets(2000, 150, 225, 56),
        proposed_targets=NutritionTargets(2000, 150, 225, 56),
        decision="safety_hold",
        confidence="low",
        evidence_ids=("evidence-1",),
        next_checkin_focus_ids=("focus-1",),
        interpretation="안전 검토가 필요합니다.",
        warnings=("low_confidence",),
        facts=(("focus-1", "안전 검토"),),
        owner_review_notes=("안전 보류: 소유자 검토 전 코칭 발송 보류",),
        revision_binding_digest="a" * 64,
    )

    payload = coach_review_to_dict(review)

    assert {field.name for field in fields(CoachReview)} == {
        "schema_version",
        "current_targets",
        "proposed_targets",
        "decision",
        "confidence",
        "evidence_ids",
        "next_checkin_focus_ids",
        "interpretation",
        "warnings",
        "facts",
        "owner_review_notes",
        "revision_binding_digest",
    }
    assert payload["owner_review_notes"] == ["안전 보류: 소유자 검토 전 코칭 발송 보류"]
    assert all("trainer" not in key for key in payload)
    assert coach_review_from_dict(payload) == review

    historical = dict(payload)
    historical["trainer_handoff"] = historical.pop("owner_review_notes")
    historical["schema_version"] = "nutrition-coach-review-v2"
    assert coach_review_from_dict(historical) is None


def test_v1_runtime_closure_has_no_trainer_scaffolding_or_projection_keys() -> None:
    repository = Path(__file__).parents[2]
    v1_runtime_sources = (
        "gateway/platforms/nutrition_coaching_proposal.py",
        "gateway/platforms/nutrition_coaching_proposal_validation.py",
        "gateway/platforms/nutrition_coaching.py",
        "gateway/platforms/telegram.py",
        "gateway/platforms/telegram_nutrition_onboarding_copy.py",
        "gateway/platforms/telegram_nutrition_operator_console.py",
        "gateway/platforms/telegram_customer_bootstrap.py",
        "gateway/platforms/telegram_customer_bootstrap_registration.py",
    )
    forbidden = re.compile(
        r"\b(?:trainer_handoff|trainer_address_for|trainer_private|"
        r"resolve_trainer|trainer_for|open_trainer_launcher|bind_trainer_launcher|"
        r"handle_trainer_(?:text|callback)|_send_coach_trainer_handoff)\b"
    )

    findings = {
        path: sorted(set(forbidden.findall((repository / path).read_text("utf-8"))))
        for path in v1_runtime_sources
    }

    assert findings == {path: [] for path in v1_runtime_sources}, json.dumps(
        findings, sort_keys=True
    )


def test_inventory_runtime_roots_have_no_trainer_token_or_namespace() -> None:
    repository = Path(__file__).parents[2]
    roots = (
        "hermes_cli/main.py",
        "gateway/platforms/telegram.py",
        "gateway/platforms/nutrition_coaching.py",
        "gateway/platforms/nutrition_coaching_proposal.py",
        "gateway/platforms/nutrition_coaching_proposal_validation.py",
        "gateway/platforms/nutrition_coaching_judgment.py",
        "gateway/platforms/nutrition_coaching_judgment_request.py",
        "gateway/platforms/nutrition_coaching_judgment_types.py",
        "gateway/platforms/telegram_customer_bootstrap.py",
        "gateway/platforms/telegram_customer_bootstrap_registration.py",
    )
    forbidden = re.compile(
        r"(?i)(^|[^a-z0-9])trainer([^a-z0-9]|$)|"
        r"trainer_[a-z0-9_]*|[a-z0-9_]*_trainer[a-z0-9_]*|"
        r"trainer-review|trainer_review|trainer-session|trainer_session|"
        r"claim_trainer|pilot_trainer|trb[0-9]+|pt1:|트레이너|오늘PT기록|PT기록"
    )
    findings = {
        path: sorted(set(match.group(0) for match in forbidden.finditer(
            (repository / path).read_text("utf-8")
        )))
        for path in roots
    }

    assert findings == {path: [] for path in roots}, json.dumps(
        findings, ensure_ascii=False, sort_keys=True
    )
