import time

import pytest

from promrs import CollectorRegistry, Counter, Gauge, Histogram, generate_latest


def test_counter_label_free_inc() -> None:
    registry = CollectorRegistry()
    c = Counter("label_free_counter", "A counter without labels", registry=registry)
    c.inc()
    c.inc(5.0)
    output = generate_latest(registry).decode()
    assert "label_free_counter_total{} 6.0" in output


def test_counter_label_free_negative_raises() -> None:
    registry = CollectorRegistry()
    c = Counter("neg_counter", "test", registry=registry)
    with pytest.raises(ValueError, match="non-negative"):
        c.inc(-1.0)


def test_counter_with_labels_direct_inc_raises() -> None:
    registry = CollectorRegistry()
    c = Counter("labeled_counter", "test", ["method"], registry=registry)
    with pytest.raises(ValueError, match="label values"):
        c.inc()


def test_gauge_label_free_set() -> None:
    registry = CollectorRegistry()
    g = Gauge("label_free_gauge", "A gauge without labels", registry=registry)
    g.set(42.0)
    output = generate_latest(registry).decode()
    assert "label_free_gauge{} 42.0" in output


def test_gauge_label_free_inc_dec() -> None:
    registry = CollectorRegistry()
    g = Gauge("inc_dec_gauge", "test", registry=registry)
    g.inc()
    g.inc(4.0)
    g.dec()
    g.dec(2.0)
    output = generate_latest(registry).decode()
    assert "inc_dec_gauge{} 2.0" in output


def test_gauge_label_free_set_to_current_time() -> None:
    registry = CollectorRegistry()
    g = Gauge("time_gauge", "test", registry=registry)
    before = time.time()
    g.set_to_current_time()
    after = time.time()
    output = generate_latest(registry).decode()
    for line in output.split("\n"):
        if line.startswith("time_gauge{"):
            value = float(line.split("} ")[1])
            assert before <= value <= after
            break
    else:
        pytest.fail("time_gauge not found in output")


def test_gauge_with_labels_direct_set_raises() -> None:
    registry = CollectorRegistry()
    g = Gauge("labeled_gauge", "test", ["host"], registry=registry)
    with pytest.raises(ValueError, match="label values"):
        g.set(1.0)


def test_gauge_child_set_to_current_time() -> None:
    registry = CollectorRegistry()
    g = Gauge("child_time_gauge", "test", ["k"], registry=registry)
    before = time.time()
    g.labels(k="v").set_to_current_time()
    after = time.time()
    output = generate_latest(registry).decode()
    for line in output.split("\n"):
        if line.startswith("child_time_gauge{"):
            value = float(line.split("} ")[1])
            assert before <= value <= after
            break
    else:
        pytest.fail("child_time_gauge not found in output")


def test_histogram_label_free_observe() -> None:
    registry = CollectorRegistry()
    h = Histogram("label_free_hist", "A histogram without labels", registry=registry, buckets=[0.1, 0.5, 1.0])
    h.observe(0.3)
    h.observe(0.7)
    output = generate_latest(registry).decode()
    assert 'label_free_hist_bucket{le="0.1"} 0' in output
    assert 'label_free_hist_bucket{le="0.5"} 1' in output
    assert 'label_free_hist_bucket{le="1.0"} 2' in output
    assert "label_free_hist_count{} 2" in output


def test_histogram_with_labels_direct_observe_raises() -> None:
    registry = CollectorRegistry()
    h = Histogram("labeled_hist", "test", ["op"], registry=registry, buckets=[1.0])
    with pytest.raises(ValueError, match="label values"):
        h.observe(0.5)
