from datetime import date

from fastapi.testclient import TestClient

from app.main import app


def _required_task_id(payload):
    for child in payload["children"]:
        for task in child["tasks"]["open"]:
            if task["kind"] == "required":
                return child["child"]["id"], task["id"]
    raise AssertionError("no required task found")


def _bonus_task_id(payload):
    for child in payload["children"]:
        for task in child["tasks"]["open"]:
            if task["kind"] == "bonus":
                return child["child"]["id"], task["id"]
    raise AssertionError("no bonus task found")


def test_past_open_required_task_books_penalty_once():
    with TestClient(app) as client:
        dashboard = client.get("/api/dashboard?date=2026-06-01").json()
        child_id, _task_id = _required_task_id(dashboard)
        first_ledger = client.get(f"/api/coins/{child_id}/ledger").json()
        client.get("/api/dashboard?date=2026-06-01")
        second_ledger = client.get(f"/api/coins/{child_id}/ledger").json()

    assert first_ledger["summary"] == {"posted": -2, "reserved": 0, "available": -2}
    penalties = [tx for tx in second_ledger["transactions"] if tx["transaction_type"] == "penalty"]
    assert len(penalties) == 2
    assert second_ledger["summary"] == first_ledger["summary"]


def test_late_required_completion_reverses_penalty_once():
    with TestClient(app) as client:
        dashboard = client.get("/api/dashboard?date=2026-06-02").json()
        child_id, task_id = _required_task_id(dashboard)
        before = client.get(f"/api/coins/{child_id}/ledger").json()["summary"]
        complete = client.post(f"/api/tasks/{task_id}/complete", json={"idempotency_key": "late-required"})
        second = client.post(f"/api/tasks/{task_id}/complete", json={"idempotency_key": "late-required"})
        ledger = client.get(f"/api/coins/{child_id}/ledger").json()

    assert before == {"posted": -2, "reserved": 0, "available": -2}
    assert complete.status_code == 200
    assert any(tx["transaction_type"] == "penalty_reversal" and tx["amount"] == 1 for tx in complete.json()["coin_transactions"])
    assert second.json()["idempotent"] is True
    assert ledger["summary"] == {"posted": -1, "reserved": 0, "available": -1}
    reversals = [tx for tx in ledger["transactions"] if tx["transaction_type"] == "penalty_reversal"]
    assert len(reversals) == 1


def test_bonus_tasks_do_not_receive_day_close_penalty():
    with TestClient(app) as client:
        dashboard = client.get("/api/dashboard?date=2026-06-03").json()
        child_id, _task_id = _bonus_task_id(dashboard)
        ledger = client.get(f"/api/coins/{child_id}/ledger").json()

    assert all(tx["task_instance_id"] != _task_id for tx in ledger["transactions"])
