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 CoinTransaction, DailyMathAssignment
from tests.conftest import admin_headers


def test_daily_math_quiz_is_stable_and_persists_answer():
    init_db()
    with TestClient(app) as client:
        first = client.get('/api/daily-math/quiz?date=2026-06-17')
        second = client.get('/api/daily-math/quiz?date=2026-06-17')
        item = first.json()['items'][0]
        answer = client.post('/api/daily-math/quiz-answer', json={
            'child_id': item['child_id'],
            'date': item['date'],
            'task_id': item['task']['id'],
            'selected_answer': item['task']['options'][0],
        })
        after = client.get('/api/daily-math/quiz?date=2026-06-17')

    assert first.status_code == 200
    assert second.status_code == 200
    assert first.json()['items'][0]['task']['prompt'] == second.json()['items'][0]['task']['prompt']
    assert answer.status_code == 200
    assert after.json()['items'][0]['answered'] is True


def test_admin_child_quiz_settings_update_and_public_sound_setting():
    init_db()
    with TestClient(app) as client:
        headers = admin_headers(client)
        child = client.get('/api/admin/children', headers=headers).json()['children'][0]
        updated = client.patch(f"/api/admin/children/{child['id']}/settings", headers=headers, json={'math_quiz_level': 4, 'language_quiz_level': 2})
        sound = client.patch('/api/admin/settings/departure_warning_sound_enabled', headers=headers, json={'value': 'false', 'description': 'Test'})
        math_coin = client.patch('/api/admin/settings/math_quiz_coin_value', headers=headers, json={'value': '2', 'description': 'Test Coins'})
        public = client.get('/api/admin/settings/public')

    assert updated.status_code == 200
    assert updated.json()['child']['settings']['math_quiz_level'] == 4
    assert updated.json()['child']['settings']['language_quiz_level'] == 2
    assert sound.status_code == 200
    assert math_coin.status_code == 200
    assert public.json()['departure_warning_sound_enabled'] is False
    assert public.json()['math_quiz_coin_value'] == 2


def test_daily_math_correct_answer_awards_coin_once_and_wrong_awards_none():
    init_db()
    with TestClient(app) as client:
        correct_quiz = client.get('/api/daily-math/quiz?date=2026-06-18')
        correct_item = correct_quiz.json()['items'][0]
        with Session(engine) as session:
            correct_assignment = session.exec(select(DailyMathAssignment).where(DailyMathAssignment.child_id == correct_item['child_id'], DailyMathAssignment.day == correct_item['date'])).one()
            correct_answer = correct_assignment.correct_answer
        response = client.post('/api/daily-math/quiz-answer', json={
            'child_id': correct_item['child_id'],
            'date': correct_item['date'],
            'task_id': correct_item['task']['id'],
            'selected_answer': correct_answer,
        })
        duplicate = client.post('/api/daily-math/quiz-answer', json={
            'child_id': correct_item['child_id'],
            'date': correct_item['date'],
            'task_id': correct_item['task']['id'],
            'selected_answer': correct_answer,
        })

        wrong_item = client.get('/api/daily-math/quiz?date=2026-06-19').json()['items'][1]
        with Session(engine) as session:
            wrong_assignment = session.exec(select(DailyMathAssignment).where(DailyMathAssignment.child_id == wrong_item['child_id'], DailyMathAssignment.day == wrong_item['date'])).one()
            wrong = wrong_assignment.wrong_option_1
        wrong_response = client.post('/api/daily-math/quiz-answer', json={
            'child_id': wrong_item['child_id'],
            'date': wrong_item['date'],
            'task_id': wrong_item['task']['id'],
            'selected_answer': wrong,
        })

    assert response.status_code == 200
    assert response.json()['coin_awarded'] is True
    assert duplicate.json()['coin_awarded'] is False
    assert duplicate.json()['idempotent'] is True
    assert wrong_response.status_code == 200
    assert wrong_response.json()['coin_awarded'] is False
    with Session(engine) as session:
        txs = session.exec(select(CoinTransaction)).all()
        assert sum(tx.amount for tx in txs if tx.comment.startswith('Rechnung des Tages')) == response.json()['coin_value']
