from datetime import date

from fastapi.testclient import TestClient
from sqlmodel import Session, select

from app.db.session import engine, init_db
from app.main import app
from app.models import Child, ChildSettings, CoinTransaction, DailyKnowledgeAssignment
from app.services.daily_math import generate_task


def test_daily_math_no_half_of_prompt():
    init_db()
    child = Child(id=99, name='Testkind', color='#fff', avatar='🧪', sort_order=99)
    prompts = [generate_task(child, level, date(2026, 6, day))['prompt'] for level in (3, 4) for day in range(1, 29)]
    assert all('1/2 von' not in prompt for prompt in prompts)
    assert all('1/4 von' not in prompt for prompt in prompts)
    assert any(' : ' in prompt for prompt in prompts)


def test_daily_knowledge_assignment_stable():
    init_db()
    with TestClient(app) as client:
        first = client.get('/api/daily-knowledge/quiz?date=2026-06-18')
        second = client.get('/api/daily-knowledge/quiz?date=2026-06-18')
    assert first.status_code == 200
    assert second.status_code == 200
    assert first.json()['items'][0]['question']['id'] == second.json()['items'][0]['question']['id']
    assert first.json()['items'][0]['question']['question'] == second.json()['items'][0]['question']['question']


def test_daily_knowledge_correct_answer_awards_coin():
    init_db()
    with TestClient(app) as client:
        quiz = client.get('/api/daily-knowledge/quiz?date=2026-06-18')
        item = quiz.json()['items'][0]
        with Session(engine) as session:
            assignment = session.exec(select(DailyKnowledgeAssignment).where(DailyKnowledgeAssignment.child_id == item['child_id'], DailyKnowledgeAssignment.day == item['date'])).one()
            correct = assignment.correct_answer
        response = client.post('/api/daily-knowledge/quiz-answer', json={
            'child_id': item['child_id'],
            'date': item['date'],
            'question_id': item['question']['id'],
            'selected_answer': correct,
        })
    assert response.status_code == 200
    assert response.json()['correct'] is True
    assert response.json()['coin_awarded'] is True
    with Session(engine) as session:
        tx = session.exec(select(CoinTransaction).where(CoinTransaction.comment == 'Allgemeinwissen des Tages richtig beantwortet')).one()
        assert tx.amount == response.json()['coin_value'] == 1


def test_daily_knowledge_wrong_answer_no_coin():
    init_db()
    with TestClient(app) as client:
        quiz = client.get('/api/daily-knowledge/quiz?date=2026-06-19')
        item = quiz.json()['items'][1]
        with Session(engine) as session:
            assignment = session.exec(select(DailyKnowledgeAssignment).where(DailyKnowledgeAssignment.child_id == item['child_id'], DailyKnowledgeAssignment.day == item['date'])).one()
            wrong = assignment.wrong_option_1
        response = client.post('/api/daily-knowledge/quiz-answer', json={
            'child_id': item['child_id'],
            'date': item['date'],
            'question_id': item['question']['id'],
            'selected_answer': wrong,
        })
    assert response.status_code == 200
    assert response.json()['correct'] is False
    assert response.json()['coin_awarded'] is False
    with Session(engine) as session:
        txs = session.exec(select(CoinTransaction).where(CoinTransaction.comment == 'Allgemeinwissen des Tages richtig beantwortet')).all()
        assert txs == []


def test_daily_knowledge_idempotent_no_double_coin():
    init_db()
    with TestClient(app) as client:
        quiz = client.get('/api/daily-knowledge/quiz?date=2026-06-20')
        item = quiz.json()['items'][0]
        with Session(engine) as session:
            assignment = session.exec(select(DailyKnowledgeAssignment).where(DailyKnowledgeAssignment.child_id == item['child_id'], DailyKnowledgeAssignment.day == item['date'])).one()
            correct = assignment.correct_answer
        body = {'child_id': item['child_id'], 'date': item['date'], 'question_id': item['question']['id'], 'selected_answer': correct}
        first = client.post('/api/daily-knowledge/quiz-answer', json=body)
        second = client.post('/api/daily-knowledge/quiz-answer', json=body)
    assert first.json()['coin_awarded'] is True
    assert second.json()['coin_awarded'] is False
    assert second.json()['idempotent'] is True
    with Session(engine) as session:
        txs = session.exec(select(CoinTransaction).where(CoinTransaction.idempotency_key.startswith('daily-knowledge-quiz:'))).all()
        assert len(txs) == 1


def test_daily_knowledge_uses_child_level():
    init_db()
    with Session(engine) as session:
        emilia = session.exec(select(Child).where(Child.name == 'Emilia')).one()
        valerie = session.exec(select(Child).where(Child.name == 'Valerie')).one()
        emilia_settings = session.exec(select(ChildSettings).where(ChildSettings.child_id == emilia.id)).one()
        valerie_settings = session.exec(select(ChildSettings).where(ChildSettings.child_id == valerie.id)).one()
        emilia_settings.knowledge_quiz_level = 4
        valerie_settings.knowledge_quiz_level = 2
        session.add(emilia_settings); session.add(valerie_settings); session.commit()
    with TestClient(app) as client:
        quiz = client.get('/api/daily-knowledge/quiz?date=2026-06-21').json()
    levels = {item['child_name']: item['question']['level'] for item in quiz['items']}
    assert levels['Emilia'] == 4
    assert levels['Valerie'] == 2
