# retoor <retoor@molodetz.nl>

import base64
import io
from datetime import datetime, timezone

import pytest
from PIL import Image
from devplacepy.database import (
    get_award_usage,
    get_table,
    init_db,
    recompute_user_award_stats,
)
from devplacepy.services.jobs.award_service import AwardService
from devplacepy.utils import generate_uid, make_combined_slug
from tests.conftest import run_async


@pytest.fixture(autouse=True)
def _db(local_db, tmp_path, monkeypatch):
    init_db()
    monkeypatch.setattr("devplacepy.attachments.ATTACHMENTS_DIR", tmp_path / "attachments")
    yield


def _png_bytes():
    buf = io.BytesIO()
    Image.new("RGBA", (64, 64), (40, 80, 120, 255)).save(buf, format="PNG")
    return buf.getvalue()


class _FakeResponse:
    def __init__(self, payload, headers=None):
        self._payload = payload
        self.headers = headers or {}

    def raise_for_status(self):
        return None

    def json(self):
        return self._payload


class _FakeClient:
    def __init__(self, *args, **kwargs):
        self._png = _png_bytes()

    def __enter__(self):
        return self

    def __exit__(self, *args):
        return False

    def post(self, url, json=None, headers=None):
        encoded = base64.b64encode(self._png).decode("ascii")
        return _FakeResponse(
            {"data": [{"b64_json": encoded}]},
            headers={
                "X-Gateway-Cost-USD": "0.001",
                "X-Gateway-Prompt-Tokens": "10",
                "X-Gateway-Completion-Tokens": "0",
                "X-Gateway-Total-Tokens": "10",
                "X-Gateway-Upstream-Latency-Ms": "100",
                "X-Gateway-Total-Latency-Ms": "120",
            },
        )


def _seed_pending(giver_uid, receiver_uid, description="Nice job"):
    uid = generate_uid()
    slug = make_combined_slug(description, uid)
    get_table("awards").insert(
        {
            "uid": uid,
            "slug": slug,
            "description": description,
            "giver_uid": giver_uid,
            "receiver_uid": receiver_uid,
            "attachment_uid_512": "",
            "attachment_uid_256": "",
            "attachment_uid_64": "",
            "generated_at": None,
            "created_at": datetime.now(timezone.utc).isoformat(),
            "job_uid": "",
            "deleted_at": None,
            "deleted_by": None,
        }
    )
    return uid, slug


def _user(prefix):
    uid = generate_uid()
    get_table("users").insert(
        {
            "uid": uid,
            "username": f"{prefix}_{uid[:8]}",
            "terms_version": "1",
            "email": f"{uid[:8]}@t.dev",
            "api_key": generate_uid(),
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return uid


def _job(award_uid, giver_uid, receiver_uid, api_key):
    return {
        "uid": generate_uid(),
        "payload": {
            "award_uid": award_uid,
            "giver_uid": giver_uid,
            "receiver_uid": receiver_uid,
            "description": "Nice job",
            "api_key": api_key,
        },
    }


def test_process_finalizes_award(monkeypatch):
    monkeypatch.setattr("devplacepy.services.jobs.award_service.stealth.stealth_sync_client", _FakeClient)
    giver = _user("giver")
    receiver = _user("recv")
    api_key = get_table("users").find_one(uid=giver)["api_key"]
    award_uid, _ = _seed_pending(giver, receiver)
    run_async(AwardService().process(_job(award_uid, giver, receiver, api_key)))
    row = get_table("awards").find_one(uid=award_uid)
    assert row.get("generated_at")
    assert row.get("attachment_uid_512")
    assert row.get("attachment_uid_256")
    assert row.get("attachment_uid_64")
    recompute_user_award_stats(receiver)
    user = get_table("users").find_one(uid=receiver)
    assert user.get("award_count") == 1


def test_process_is_idempotent(monkeypatch):
    monkeypatch.setattr("devplacepy.services.jobs.award_service.stealth.stealth_sync_client", _FakeClient)
    giver = _user("giver2")
    receiver = _user("recv2")
    api_key = get_table("users").find_one(uid=giver)["api_key"]
    award_uid, _ = _seed_pending(giver, receiver)
    job = _job(award_uid, giver, receiver, api_key)
    svc = AwardService()
    run_async(svc.process(job))
    first = get_table("awards").find_one(uid=award_uid)
    run_async(svc.process(job))
    second = get_table("awards").find_one(uid=award_uid)
    assert first["generated_at"] == second["generated_at"]
    assert first["attachment_uid_512"] == second["attachment_uid_512"]


def test_process_skips_soft_deleted_award(monkeypatch):
    monkeypatch.setattr("devplacepy.services.jobs.award_service.stealth.stealth_sync_client", _FakeClient)
    giver = _user("giver3")
    receiver = _user("recv3")
    api_key = get_table("users").find_one(uid=giver)["api_key"]
    award_uid, _ = _seed_pending(giver, receiver)
    get_table("awards").update(
        {"uid": award_uid, "deleted_at": datetime.now(timezone.utc).isoformat(), "deleted_by": giver},
        ["uid"],
    )
    result = run_async(AwardService().process(_job(award_uid, giver, receiver, api_key)))
    assert result.get("skipped") is True
    assert not get_table("awards").find_one(uid=award_uid).get("generated_at")


def test_award_usage_accumulates_from_gateway_headers(monkeypatch):
    monkeypatch.setattr("devplacepy.services.jobs.award_service.stealth.stealth_sync_client", _FakeClient)
    get_table("award_usage").delete()
    giver = _user("giver4")
    receiver = _user("recv4")
    api_key = get_table("users").find_one(uid=giver)["api_key"]
    award_uid, _ = _seed_pending(giver, receiver)
    run_async(AwardService().process(_job(award_uid, giver, receiver, api_key)))
    usage = get_award_usage()
    assert usage["calls"] >= 1
    assert usage["cost_usd"] > 0