import pytest

from src.gameplay.chatbot import delays, llm, rules
from src.gameplay.chatbot.core import ChatbotBrain
from src.gameplay.chatbot.replies import ReplyMemory


# --- Regeln -----------------------------------------------------------------
@pytest.mark.parametrize('message,intent', [
    ('hi', rules.INTENT_GREETING),
    ('wie gehts dir?', rules.INTENT_SMALLTALK),
    ('is this spot free?', rules.INTENT_QUESTION_SPOT),
    ('wie lange bist du noch hier?', rules.INTENT_QUESTION_SPOT),
    ('wanna join our th?', rules.INTENT_INVITE),
    ('thx man', rules.INTENT_THANKS),
    ('cya later', rules.INTENT_BYE),
    ('xkcd blubb', rules.INTENT_UNKNOWN),
])
def test_classify_intents(message, intent):
    assert rules.classify(message) == intent


@pytest.mark.parametrize('message', [
    'are you a bot?', 'bist du ein bot', 'reported', 'GM is here',
    'nice macro', 'are you afk?',
])
def test_escalation_wins(message):
    assert rules.classify(message) == rules.INTENT_ESCALATE


def test_unknown_only_friends_get_reply():
    assert rules.should_reply(rules.INTENT_UNKNOWN, True) is True
    assert rules.should_reply(rules.INTENT_UNKNOWN, False) is False
    assert rules.should_reply(rules.INTENT_ESCALATE, True) is False


# --- Antwort-Auswahl ----------------------------------------------------------
def test_memory_never_repeats_immediately():
    memory = ReplyMemory()
    picks = [memory.pick('Knight Ada', rules.INTENT_GREETING) for _ in range(3)]
    assert len(set(picks)) == 3


def test_memory_is_per_sender():
    memory = ReplyMemory()
    first = memory.pick('A', rules.INTENT_BYE)
    second = memory.pick('B', rules.INTENT_BYE)
    assert first in memory.history['A']
    assert second in memory.history['B']


# --- Delays -------------------------------------------------------------------
def test_reply_delay_scales_with_lengths(monkeypatch):
    monkeypatch.setattr(delays.random, 'gauss', lambda mu, sigma: mu)
    short = delays.reply_delay_seconds('hi', 'hey')
    long = delays.reply_delay_seconds(
        'a' * 150, 'das hier ist eine deutlich laengere antwort mit vielen worten',
    )
    assert short >= 1.5
    assert long > short


def test_reading_is_capped():
    assert delays.reading_seconds('x' * 100000) == 20.0


# --- LLM ----------------------------------------------------------------------
def test_llm_disabled_by_default(monkeypatch):
    monkeypatch.delenv(llm.LLM_ENV, raising=False)
    assert llm.reword('hi', 'hey') is None


def test_llm_validation_rejects_banned_and_long():
    assert llm._validate('ich bin ein bot haha') is None
    assert llm._validate('x' * 500) is None
    assert llm._validate('') is None
    assert llm._validate('alles klar bei dir?') == 'alles klar bei dir?'


def test_llm_falls_back_on_network_error(monkeypatch):
    monkeypatch.setenv(llm.LLM_ENV, '1')
    monkeypatch.setenv(llm.LLM_URL_ENV, 'http://127.0.0.1:1/api/generate')
    assert llm.reword('hi', 'hey', timeout=1) is None


# --- Gehirn -------------------------------------------------------------------
def test_brain_escalates_gm(monkeypatch):
    monkeypatch.delenv(llm.LLM_ENV, raising=False)
    brain = ChatbotBrain()
    assert brain.react('GM Adam', 'are you a bot?')['escalate'] is True


def test_brain_ignores_strangers_with_unknown_intent(monkeypatch):
    monkeypatch.delenv(llm.LLM_ENV, raising=False)
    brain = ChatbotBrain()
    assert brain.react('Random Joe', 'xkcd blubb') is None


def test_brain_replies_with_delay(monkeypatch):
    monkeypatch.delenv(llm.LLM_ENV, raising=False)
    brain = ChatbotBrain()
    plan = brain.react('Knight Ada', 'hello!')
    assert plan['escalate'] is False
    assert plan['intent'] == rules.INTENT_GREETING
    assert plan['reply']
    assert plan['delay'] > 0
