import pytest
import json
import uuid
import asyncio
from app.core.postgres.erp_client import ErpDatabaseClient
from app.core.module_framework.event_bus import event_bus
from app.core.module_framework.outbox_worker import process_outbox_events

# Need to run process_outbox_events briefly to let it process
def test_transactional_outbox():
    asyncio.run(_async_test_transactional_outbox())

async def _async_test_transactional_outbox():
    db = ErpDatabaseClient()
    
    # 1. Clear outbox for a clean slate
    with db.get_connection() as conn, conn.cursor() as cur:
        cur.execute("DELETE FROM erp_outbox_events")
        conn.commit()
        
    test_payload = {"test": "data", "id": uuid.uuid4()}
    
    # 2. Write an event in a transaction
    with db.get_connection() as conn, conn.cursor() as cur:
        event_bus.publish_outbox(cur, "test.event", test_payload)
        conn.commit()
        
    # 3. Verify it's in the outbox as 'pending'
    with db.get_connection() as conn, conn.cursor() as cur:
        cur.execute("SELECT status FROM erp_outbox_events WHERE event_type = 'test.event'")
        row = cur.fetchone()
        assert row is not None
        assert row["status"] == "pending"
        
    # 4. Subscribe a dummy handler
    received = []
    def dummy_handler(payload):
        received.append(payload)
        
    event_bus.subscribe("test.event", dummy_handler)
    
    # 5. Run the worker briefly.
    worker_task = asyncio.create_task(process_outbox_events())
    await asyncio.sleep(0.5) # Let it run
    worker_task.cancel() # Stop it
    
    # 6. Verify event was received
    assert len(received) == 1
    assert received[0]["test"] == "data"
    
    # 7. Verify status in outbox changed to completed
    with db.get_connection() as conn, conn.cursor() as cur:
        cur.execute("SELECT status FROM erp_outbox_events WHERE event_type = 'test.event'")
        row = cur.fetchone()
        assert row["status"] == "completed"
