import json
import urllib.error
import urllib.parse
import urllib.request

from tests._pytest_port import BASE, TEST_STATE_DIR


def _get_logs(file="agent", tail=200):
    url = f"{BASE}/api/logs?file={urllib.parse.quote(str(file))}&tail={urllib.parse.quote(str(tail))}"
    with urllib.request.urlopen(url, timeout=10) as r:
        return json.loads(r.read()), r.status


def _get_logs_error(file="agent", tail=200):
    url = f"{BASE}/api/logs?file={urllib.parse.quote(str(file))}&tail={urllib.parse.quote(str(tail))}"
    try:
        with urllib.request.urlopen(url, timeout=10) as r:
            return json.loads(r.read()), r.status
    except urllib.error.HTTPError as e:
        return json.loads(e.read()), e.code


def test_logs_endpoint_tails_whitelisted_synthetic_agent_log():
    logs_dir = TEST_STATE_DIR / "logs"
    logs_dir.mkdir(parents=True, exist_ok=True)
    (logs_dir / "agent.log").write_text(
        "\n".join(
            [f"2026-05-04 INFO synthetic-log-marker line {i}" for i in range(105)]
            + ["2026-05-04 ERROR synthetic-log-marker failed safely"]
        ) + "\n",
        encoding="utf-8",
    )

    data, status = _get_logs("agent", 100)

    assert status == 200
    assert data["file"] == "agent"
    assert data["tail"] == 100
    assert len(data["lines"]) == 100
    assert data["lines"][0] == "2026-05-04 INFO synthetic-log-marker line 6"
    assert data["lines"][-1] == "2026-05-04 ERROR synthetic-log-marker failed safely"
    assert data["truncated"] is False
    assert data["total_bytes"] > 0
    assert data["mtime"] > 0
    assert data.get("hint") == ""


def test_logs_endpoint_rejects_path_traversal_and_unknown_files():
    for bad_file in ("../../etc/passwd", "agent.log", "private", "/tmp/agent"):
        data, status = _get_logs_error(bad_file, 200)
        assert status == 400
        assert "error" in data


def test_logs_endpoint_missing_file_returns_empty_lines_with_safe_hint():
    missing = TEST_STATE_DIR / "logs" / "gateway.log"
    if missing.exists():
        missing.unlink()

    data, status = _get_logs("gateway", 200)

    assert status == 200
    assert data["file"] == "gateway"
    assert data["lines"] == []
    assert data["truncated"] is False
    assert data["total_bytes"] == 0
    assert data["mtime"] is None
    assert "not found" in data["hint"].lower()
    assert str(TEST_STATE_DIR) not in data["hint"]


def test_logs_endpoint_tail_selector_is_allowlisted_and_defaults_to_200():
    logs_dir = TEST_STATE_DIR / "logs"
    logs_dir.mkdir(parents=True, exist_ok=True)
    (logs_dir / "errors.log").write_text(
        "\n".join(f"2026-05-04 ERROR synthetic-log-marker line {i}" for i in range(250)) + "\n",
        encoding="utf-8",
    )

    default_data, default_status = _get_logs("errors", "not-a-number")
    capped_data, capped_status = _get_logs("errors", 999999)
    allowed_data, allowed_status = _get_logs("errors", 100)

    assert default_status == capped_status == allowed_status == 200
    assert default_data["tail"] == 200
    assert len(default_data["lines"]) == 200
    assert capped_data["tail"] == 200
    assert len(capped_data["lines"]) == 200
    assert allowed_data["tail"] == 100
    assert len(allowed_data["lines"]) == 100


def test_logs_endpoint_reads_bounded_window_and_reports_truncation():
    logs_dir = TEST_STATE_DIR / "logs"
    logs_dir.mkdir(parents=True, exist_ok=True)
    huge_prefix = "x" * (4 * 1024 * 1024 + 64)
    (logs_dir / "gateway.log").write_text(
        huge_prefix + "\n2026-05-04 INFO synthetic-log-marker tail survives\n",
        encoding="utf-8",
    )

    data, status = _get_logs("gateway", 1000)

    assert status == 200
    assert data["tail"] == 1000
    assert data["truncated"] is True
    assert data["lines"][-1] == "2026-05-04 INFO synthetic-log-marker tail survives"
    assert data["total_bytes"] > 4 * 1024 * 1024


def test_logs_endpoint_tests_use_only_synthetic_fixture_content():
    source = __import__("pathlib").Path(__file__).read_text(encoding="utf-8")
    assert "synthetic-log-marker" in source
    assert "/home/" + "michael" not in source
    assert "~/" + ".hermes/logs" not in source
    assert "TOK" + "EN=" not in source
    assert "PASS" + "WORD=" not in source
