"""Portable local-launcher rendering and filesystem contracts."""

from __future__ import annotations

import sys
from types import SimpleNamespace
from unittest.mock import Mock, mock_open

from obliteratus import local_ui


class _EncodingOnlyStdout:
    def __init__(self, encoding: str | None) -> None:
        self.encoding = encoding


def test_local_ui_banner_degrades_to_ascii_on_cp1252(monkeypatch):
    monkeypatch.setattr(local_ui.sys, "stdout", _EncodingOnlyStdout("cp1252"))
    banner = local_ui._banner_for_console()
    assert "OBLITERATUS" in banner
    assert banner.isascii()


def test_local_ui_banner_keeps_block_art_on_utf8(monkeypatch):
    monkeypatch.setattr(local_ui.sys, "stdout", _EncodingOnlyStdout("utf-8"))
    assert "░" in local_ui._banner_for_console()


def test_system_info_queries_the_platform_temp_directory(monkeypatch, tmp_path):
    disk_free = Mock(return_value=12.5)
    monkeypatch.setattr(local_ui.tempfile, "gettempdir", lambda: str(tmp_path))
    monkeypatch.setattr(local_ui, "_get_disk_free_gb", disk_free)
    monkeypatch.setattr(local_ui, "console", Mock())

    local_ui._print_system_info([])

    disk_free.assert_called_once_with(str(tmp_path))


def test_ram_detection_falls_back_from_broken_psutil_to_proc(monkeypatch):
    broken_psutil = SimpleNamespace(
        virtual_memory=Mock(side_effect=OSError("unavailable")),
    )
    monkeypatch.setitem(sys.modules, "psutil", broken_psutil)
    monkeypatch.setattr(
        "builtins.open",
        mock_open(read_data="MemTotal:       2097152 kB\n"),
    )

    assert local_ui._get_ram_gb() == 2.0


def test_ram_detection_uses_posix_sysconf_without_psutil_or_proc(monkeypatch):
    monkeypatch.setitem(sys.modules, "psutil", None)
    monkeypatch.setattr("builtins.open", Mock(side_effect=OSError("no procfs")))
    values = {"SC_PHYS_PAGES": 1_048_576, "SC_PAGE_SIZE": 4096}
    sysconf = Mock(side_effect=values.__getitem__)
    monkeypatch.setattr(local_ui.os, "sysconf", sysconf)

    assert local_ui._get_ram_gb() == 4.0
    assert [call.args[0] for call in sysconf.call_args_list] == [
        "SC_PHYS_PAGES",
        "SC_PAGE_SIZE",
    ]


def test_ram_detection_fails_closed_when_all_probes_are_unavailable(monkeypatch):
    monkeypatch.setitem(sys.modules, "psutil", None)
    monkeypatch.setattr("builtins.open", Mock(side_effect=OSError("no procfs")))
    monkeypatch.setattr(local_ui.os, "sysconf", Mock(side_effect=OSError("unsupported")))

    assert local_ui._get_ram_gb() == 0.0
