import json
import time
import threading
import pytest
from unittest.mock import patch, MagicMock

from notilens.emitter import NotiLensEmitter


@pytest.fixture
def emitter():
    e = NotiLensEmitter(token="tok", secret="sec", agent="test-agent", silent=True)
    yield e
    e.shutdown()


def _mock_urlopen(status=200):
    resp = MagicMock()
    resp.status = status
    resp.__enter__ = lambda s: s
    resp.__exit__ = MagicMock(return_value=False)
    return resp


def test_send_queues_payload(emitter):
    with patch("urllib.request.urlopen", return_value=_mock_urlopen(200)):
        emitter.send("task.started", "hello")
        emitter.flush(timeout=3.0)


def test_send_filtered_by_level(emitter):
    delivered = []

    def fake_deliver(payload):
        delivered.append(payload)

    emitter._deliver = fake_deliver
    emitter.min_level = "error"
    emitter.send("task.progress", "ignored", level="info")
    emitter.flush(timeout=1.0)
    assert len(delivered) == 0


def test_send_passes_correct_payload(emitter):
    captured = []

    original_deliver = emitter._deliver

    def fake_deliver(payload):
        captured.append(payload)

    emitter._deliver = fake_deliver
    emitter.send("task.completed", "done", level="info", meta={"rows": 5})
    emitter.flush(timeout=2.0)

    assert len(captured) == 1
    p = captured[0]
    assert p["event"] == "task.completed"
    assert p["message"] == "done"
    assert p["type"] == "success"
    assert p["agent"] == "test-agent"
    assert p["meta"]["rows"] == 5


def test_flush_respects_timeout():
    e = NotiLensEmitter(token="tok", secret="sec", agent="test-agent", silent=True)
    start = time.time()
    e.flush(timeout=0.2)
    elapsed = time.time() - start
    assert elapsed < 1.0
    e.shutdown()


def test_level_filtering_order(emitter):
    assert emitter._level_num("debug") < emitter._level_num("info")
    assert emitter._level_num("info") < emitter._level_num("warning")
    assert emitter._level_num("warning") < emitter._level_num("error")
    assert emitter._level_num("error") < emitter._level_num("critical")


def test_unknown_level_defaults_to_info(emitter):
    assert emitter._level_num("unknown") == 1


def test_agent_included_in_payload(emitter):
    captured = []
    emitter._deliver = lambda p: captured.append(p)
    emitter.send("task.started", "hi")
    emitter.flush(timeout=2.0)
    assert captured[0]["agent"] == "test-agent"
