"""Tests for ``arautopilot.core.audit``."""

from __future__ import annotations

from pathlib import Path

import pytest

from arautopilot.core.audit import AuditEvent, AuditLog, AuditOutcome


def test_event_to_jsonl_is_single_line() -> None:
    ev = AuditEvent(
        action="engage_pilot",
        outcome=AuditOutcome.SUCCESS,
        user_id="u123",
        role="user",
    )
    line = ev.to_jsonl()
    assert "\n" not in line
    assert line.startswith("{") and line.endswith("}")


def test_event_is_immutable() -> None:
    ev = AuditEvent(action="x", outcome=AuditOutcome.SUCCESS)
    with pytest.raises((TypeError, ValueError)):
        ev.action = "y"  # type: ignore[misc]


def test_append_and_read_round_trip(tmp_path: Path) -> None:
    log = AuditLog(tmp_path / "audit.jsonl")
    e1 = AuditEvent(action="login", outcome=AuditOutcome.SUCCESS, user_id="u1")
    e2 = AuditEvent(action="engage", outcome=AuditOutcome.DENIED, user_id="u2",
                    reason="missing capability")
    log.append(e1)
    log.append(e2)
    read = log.read_all()
    assert len(read) == 2
    assert read[0].action == "login"
    assert read[1].outcome is AuditOutcome.DENIED


def test_len_counts_lines(tmp_path: Path) -> None:
    log = AuditLog(tmp_path / "audit.jsonl")
    assert len(log) == 0
    log.append(AuditEvent(action="a", outcome=AuditOutcome.SUCCESS))
    log.append(AuditEvent(action="b", outcome=AuditOutcome.SUCCESS))
    assert len(log) == 2


def test_log_file_is_created_if_missing(tmp_path: Path) -> None:
    p = tmp_path / "subdir" / "audit.jsonl"
    log = AuditLog(p)
    assert p.exists()
    assert len(log) == 0


def test_corrupt_line_raises(tmp_path: Path) -> None:
    p = tmp_path / "audit.jsonl"
    p.write_text(
        '{"action":"good","outcome":"success","timestamp":"2026-05-18T00:00:00Z"}\n'
        "this is not json\n",
        encoding="utf-8",
    )
    log = AuditLog(p)
    with pytest.raises(ValueError, match="corrupt audit line"):
        log.read_all()


def test_dual_auth_event_carries_secondary_user(tmp_path: Path) -> None:
    log = AuditLog(tmp_path / "a.jsonl")
    ev = AuditEvent(
        action="flash_firmware",
        outcome=AuditOutcome.SUCCESS,
        user_id="engineer_1",
        role="engineer",
        secondary_user_id="super_admin_alvaro",
        target="COM7:esp32-dev",
    )
    log.append(ev)
    read = log.read_all()
    assert read[0].secondary_user_id == "super_admin_alvaro"
    assert read[0].target == "COM7:esp32-dev"


def test_extra_payload_round_trips(tmp_path: Path) -> None:
    log = AuditLog(tmp_path / "a.jsonl")
    ev = AuditEvent(
        action="mode_change",
        outcome=AuditOutcome.SUCCESS,
        extra={"from": "STANDBY", "to": "HEADING_HOLD", "via": "modbus"},
    )
    log.append(ev)
    read = log.read_all()
    assert read[0].extra == {"from": "STANDBY", "to": "HEADING_HOLD", "via": "modbus"}


def test_blank_lines_are_skipped(tmp_path: Path) -> None:
    p = tmp_path / "a.jsonl"
    p.write_text(
        '{"action":"a","outcome":"success","timestamp":"2026-05-18T00:00:00Z"}\n'
        "\n"
        '{"action":"b","outcome":"denied","timestamp":"2026-05-18T00:00:01Z"}\n',
        encoding="utf-8",
    )
    log = AuditLog(p)
    events = log.read_all()
    assert len(events) == 2
