from fastapi.testclient import TestClient

from app.db.session import init_db
from app.main import app
from tests.conftest import admin_headers


def _child_id(client: TestClient) -> int:
    return client.get('/api/dashboard?date=2026-06-23').json()['children'][0]['child']['id']


def _ledger(client: TestClient, headers: dict, child_id: int) -> dict:
    response = client.get(f'/api/admin/coins/{child_id}/ledger', headers=headers)
    assert response.status_code == 200, response.text
    return response.json()


def _manual(client: TestClient, headers: dict, child_id: int, amount: int, key: str) -> int:
    response = client.post(
        '/api/admin/coins/manual',
        headers=headers,
        json={
            'child_id': child_id,
            'amount': amount,
            'comment': f'Testbuchung {key}',
            'idempotency_key': key,
        },
    )
    assert response.status_code == 200, response.text
    return response.json()['transaction']['id']


def test_admin_manual_plus_ten_booking_updates_available_balance_by_ten():
    init_db()
    with TestClient(app) as client:
        headers = admin_headers(client)
        child_id = _child_id(client)
        before = _ledger(client, headers, child_id)['summary']
        tx_id = _manual(client, headers, child_id, 10, 'manual-plus-ten')
        after = _ledger(client, headers, child_id)

    assert tx_id > 0
    assert after['summary']['posted'] == before['posted'] + 10
    assert after['summary']['reserved'] == before['reserved']
    assert after['summary']['available'] == before['available'] + 10
    assert any(tx['id'] == tx_id and tx['amount'] == 10 and tx['transaction_type'] == 'manual' for tx in after['transactions'])


def test_admin_single_void_does_not_crash_and_is_idempotent():
    init_db()
    with TestClient(app) as client:
        headers = admin_headers(client)
        child_id = _child_id(client)
        before = _ledger(client, headers, child_id)['summary']
        tx_id = _manual(client, headers, child_id, 5, 'admin-void-source')

        first = client.post(f'/api/admin/coins/{tx_id}/void', headers=headers, json={'comment': 'Storno Test', 'idempotency_key': f'void:{tx_id}'})
        second = client.post(f'/api/admin/coins/{tx_id}/void', headers=headers, json={'comment': 'Storno Test', 'idempotency_key': f'void:{tx_id}'})
        ledger = _ledger(client, headers, child_id)

    assert first.status_code == 200, first.text
    assert second.status_code == 200, second.text
    assert ledger['summary'] == before
    assert len([tx for tx in ledger['transactions'] if tx['reference_transaction_id'] == tx_id]) == 1


def test_admin_bulk_void_and_bulk_delete_selected_transactions():
    init_db()
    with TestClient(app) as client:
        headers = admin_headers(client)
        child_id = _child_id(client)
        before = _ledger(client, headers, child_id)['summary']
        first_id = _manual(client, headers, child_id, 3, 'bulk-source-1')
        second_id = _manual(client, headers, child_id, -1, 'bulk-source-2')

        bulk_void = client.post('/api/admin/coins/bulk-void', headers=headers, json={'transaction_ids': [first_id, second_id], 'comment': 'Sammelstorno', 'idempotency_key': 'bulk-test'})
        after_void = _ledger(client, headers, child_id)
        delete = client.request('DELETE', '/api/admin/coins/bulk', headers=headers, json={'child_id': child_id, 'transaction_ids': [first_id, second_id], 'confirm': 'DELETE_COIN_BUCHUNGEN'})
        after_delete = _ledger(client, headers, child_id)

    assert bulk_void.status_code == 200, bulk_void.text
    assert after_void['summary'] == before
    assert delete.status_code == 200, delete.text
    # Deleting originals also removes their dependent Sammelstorno rows so the selected history is gone cleanly.
    assert delete.json()['deleted'] == 4
    assert after_delete['summary'] == before
    assert all(tx['id'] not in {first_id, second_id} for tx in after_delete['transactions'])


def test_admin_reset_coin_history_sets_child_to_zero_and_removes_redemptions():
    init_db()
    with TestClient(app) as client:
        headers = admin_headers(client)
        child_id = _child_id(client)
        before_manual = _ledger(client, headers, child_id)['summary']
        _manual(client, headers, child_id, 7, 'reset-source')
        before = _ledger(client, headers, child_id)
        reset = client.post(f'/api/admin/coins/{child_id}/reset', headers=headers, json={'confirm': 'COINS_AUF_NULL', 'delete_redemptions': True})
        after = _ledger(client, headers, child_id)

    assert before['summary']['available'] == before_manual['available'] + 7
    assert reset.status_code == 200, reset.text
    assert reset.json()['deleted'] >= 1
    assert after['summary'] == {'posted': 0, 'reserved': 0, 'available': 0}
    assert after['transactions'] == []
