import asyncio
import json
import types

from src.fmatch.saas.workers.api_match_worker import ApiMatchWorker


class _Repo:
    def __init__(self, cfg):
        self._cfg = cfg
        self.updated = []
    async def get_job(self, job_id):
        o = types.SimpleNamespace()
        o.config = self._cfg
        return o
    async def update_job_status(self, job_id, status, results=None, error=None, results_path=None, matches_found=None):
        self.updated.append((status, results, error))


class _Storage:
    def __init__(self, body):
        self._body = body
    async def read(self, key):
        return self._body


def test_usage_metering_on_completion(monkeypatch):
    # Prepare worker with inline artifact (one row result expected)
    body = json.dumps({'profile': 'balanced', 'body': {'source': {'Company': 'Acme'}, 'candidates': [{'Name': 'Acme Inc'}]}}).encode()
    worker = ApiMatchWorker(db=None, storage=_Storage(body))
    repo = _Repo({'artifact_key': 'k', 'api_key_prefix': 'prefx123'})
    worker.job_repo = repo  # type: ignore

    # Engine/Intel fakes
    import pandas as pd
    async def fake_policy(self, **kwargs):
        return {"suggest": 0.7, "auto_link": 0.8}
    async def fake_auto(self, *args, **kwargs):
        return {"field_mappings": [{"source": "Company", "reference": "Name", "algorithm": "WRatio"}]}
    async def fake_match(self, *args, **kwargs):
        df = pd.DataFrame([{"score": 0.9, "Name": "Acme Inc"}])
        class R:
            matches = df
            engine_version = 'x'
            processing_time_ms = 1
        return R()
    from src.fmatch.saas.api.intelligence_client import IntelligenceClient
    from src.fmatch.saas.services.engine_client import EngineClient
    IntelligenceClient.get_policy = fake_policy  # type: ignore
    IntelligenceClient.auto_configure = fake_auto  # type: ignore
    EngineClient.match_records = fake_match  # type: ignore

    # Capture bump_usage calls
    calls = []
    from src.fmatch.saas.repos.api_repo import ApiRepo
    async def fake_bump(self, api_key_prefix, calls: int, matches: int, bytes_count: int):
        calls_list = calls  # avoid shadow
        pass
    async def fake_bump2(self, api_key_prefix, calls: int = 0, matches: int = 0, bytes_count: int = 0):
        calls.append((api_key_prefix, calls, matches, bytes_count))
    monkeypatch.setattr(ApiRepo, 'bump_usage', fake_bump2, raising=False)

    # Patch get_session to yield a dummy session once
    from src.fmatch.saas import db as dbmod
    async def _gen():
        yield object()
    monkeypatch.setattr(dbmod, 'get_session', _gen, raising=False)

    asyncio.get_event_loop().run_until_complete(worker.run_job('j2', 'acct', 'balanced', options={}))
    # One call, matches length 1
    assert any(c[1] == 1 and c[2] == 1 for c in calls)

