"""Unit tests for classify_line and parse_dmesg_line."""

from __future__ import annotations

import pytest


# ---------------------------------------------------------------------------
# classify_line tests
# ---------------------------------------------------------------------------

def test_classify_panic():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("Kernel panic - not syncing: Fatal exception") == "panic"


def test_classify_oops():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("Oops: 0000 [#1] SMP KPTI") == "oops"


def test_classify_kasan():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("KASAN: slab-out-of-bounds in foo+0x1c/0x50") == "kasan"


def test_classify_ubsan():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("UBSAN: shift-out-of-bounds in bar.c:42:8") == "ubsan"


def test_classify_warn():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("WARNING: CPU: 0 PID: 1234 at kernel/rcu/tree.c:3219") == "warn"


def test_classify_normal():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("Normal kernel message here") == "normal"


def test_classify_panic_wins_over_warn():
    """Priority ordering: panic matches before warn on same line."""
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("Kernel panic with WARNING: nested") == "panic"


def test_classify_empty_string():
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("") == "normal"


def test_classify_pattern_embedded_in_text():
    """Pattern matching works when embedded in longer text."""
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("some text KASAN: report here trailing") == "kasan"


def test_classify_oops_wins_over_kasan():
    """Oops has higher priority than KASAN."""
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("Oops: 0000 KASAN: overlap") == "oops"


def test_classify_kasan_wins_over_warn():
    """KASAN has higher priority than warn."""
    from vmcluster_mcp.observe.classifier import classify_line
    assert classify_line("KASAN: issue WARNING: something") == "kasan"


# ---------------------------------------------------------------------------
# parse_dmesg_line tests
# ---------------------------------------------------------------------------

def test_parse_raw_kern_info():
    """<6>[    0.000000] text → level=info, facility=kern, timestamp=0.0"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<6>[    0.000000] Linux version 6.1.0")
    assert line is not None
    assert line.level == "info"
    assert line.facility == "kern"
    assert line.timestamp == 0.0
    assert line.text == "Linux version 6.1.0"
    assert line.classified_as == "normal"


def test_parse_raw_kern_warning():
    """<4>[   12.345678] WARNING: CPU: 0 → level=warning, classified_as=warn"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<4>[   12.345678] WARNING: CPU: 0")
    assert line is not None
    assert line.level == "warning"
    assert line.facility == "kern"
    assert line.timestamp == pytest.approx(12.345678)
    assert line.text == "WARNING: CPU: 0"
    assert line.classified_as == "warn"


def test_parse_raw_user_info_marker():
    """<14>[  100.000000] vmcluster-marker-abc → facility=user (14>>3=1)"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<14>[  100.000000] vmcluster-marker-abc")
    assert line is not None
    assert line.level == "info"    # 14 & 7 = 6 = info
    assert line.facility == "user"  # 14 >> 3 = 1 = user
    assert line.timestamp == pytest.approx(100.0)
    assert line.text == "vmcluster-marker-abc"
    assert line.classified_as == "normal"


def test_parse_raw_alert():
    """<1>[   99.999999] Kernel panic → level=alert, classified_as=panic"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<1>[   99.999999] Kernel panic")
    assert line is not None
    assert line.level == "alert"   # 1 & 7 = 1 = alert
    assert line.facility == "kern"  # 1 >> 3 = 0 = kern
    assert line.timestamp == pytest.approx(99.999999)
    assert line.classified_as == "panic"


def test_parse_garbage_returns_none():
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    assert parse_dmesg_line("garbage line no format") is None


def test_parse_empty_string_returns_none():
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    assert parse_dmesg_line("") is None


def test_parse_iso_format():
    """ISO timestamp format: <6>2024-01-15T10:30:00,000001+0000 text"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<6>2024-01-15T10:30:00,000001+0000 Linux version")
    assert line is not None
    assert line.level == "info"
    assert line.facility == "kern"
    # Timestamp should be a float (Unix epoch)
    assert isinstance(line.timestamp, float)
    assert line.text == "Linux version"


def test_parse_not_padded_timestamp():
    """Timestamp bracket without padding: <6>[0.000001] text"""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<6>[0.000001] minimal")
    assert line is not None
    assert line.level == "info"
    assert line.timestamp == pytest.approx(0.000001)
    assert line.text == "minimal"


def test_parse_classification_applied():
    """parse_dmesg_line applies classify_line to text."""
    from vmcluster_mcp.observe.dmesg import parse_dmesg_line
    line = parse_dmesg_line("<3>[   5.000000] Oops: 0000 [#1] SMP")
    assert line is not None
    assert line.classified_as == "oops"
