"""host_desktop_open：打开 URL / 在文件管理器中显示路径（可 mock 子进程）。"""

from __future__ import annotations

from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from aicd.tools.host_desktop_open import open_url_with_browser, reveal_path_in_file_manager


def test_open_url_rejects_bad_scheme() -> None:
    r = open_url_with_browser("javascript:alert(1)", policy_check=None)
    assert r.get("ok") is False
    assert "unsupported" in (r.get("error") or "").lower()


def test_open_file_url_without_policy() -> None:
    r = open_url_with_browser("file:///tmp/x.html", policy_check=None)
    assert r.get("ok") is False
    assert "file" in (r.get("error") or "").lower()


def test_open_file_url_permission(tmp_path: Path) -> None:
    f = tmp_path / "a.html"
    f.write_text("x", encoding="utf-8")

    def deny(_p: Path) -> None:
        raise PermissionError("not allowed")

    r = open_url_with_browser(f.as_uri(), policy_check=deny)
    assert r.get("ok") is False
    assert "not allowed" in (r.get("error") or "")


@patch("aicd.tools.host_desktop_open.webbrowser.open", return_value=True)
def test_open_http_delegates_to_webbrowser(mock_open: MagicMock) -> None:
    r = open_url_with_browser("https://example.com", policy_check=None)
    assert r.get("ok") is True
    assert r.get("opened") is True
    mock_open.assert_called_once()


@patch(
    "aicd.tools.host_desktop_open.webbrowser.open",
    side_effect=RuntimeError("no display"),
)
def test_open_url_swallows_webbrowser_exception(_mock_open: MagicMock) -> None:
    r = open_url_with_browser("https://example.com", policy_check=None)
    assert r.get("ok") is False
    assert "webbrowser.open failed" in (r.get("error") or "")


def test_reveal_linux_xdg_fallback(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr("sys.platform", "linux")
    f = tmp_path / "x.txt"
    f.write_text("a", encoding="utf-8")
    with patch("aicd.tools.host_desktop_open.shutil.which") as w:
        w.side_effect = lambda name: "/usr/bin/xdg-open" if name == "xdg-open" else None
        with patch("aicd.tools.host_desktop_open._popen_detached") as pop:
            pop.return_value = MagicMock()
            r = reveal_path_in_file_manager(f)
    assert r.get("ok") is True
    assert r.get("method") == "xdg-open"
    pop.assert_called_once()


def test_reveal_linux_no_xdg(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr("sys.platform", "linux")
    f = tmp_path / "a.txt"
    f.write_text("x", encoding="utf-8")
    with patch("aicd.tools.host_desktop_open.shutil.which", return_value=None):
        r = reveal_path_in_file_manager(f)
    assert r.get("ok") is False
    assert "xdg-open" in (r.get("error") or "")


def test_reveal_macos_open(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr("sys.platform", "darwin")
    f = tmp_path / "b.txt"
    f.write_text("y", encoding="utf-8")
    with patch("aicd.tools.host_desktop_open._popen_detached") as pop:
        pop.return_value = MagicMock()
        r = reveal_path_in_file_manager(f)
    assert r.get("ok") is True
    pop.assert_called_once()
    assert pop.call_args[0][0][:2] == ["open", "-R"]
