from __future__ import annotations

from pathlib import Path

import pytest

from reddit_mcp import cookie_manager


@pytest.mark.anyio
async def test_setup_cookies_uses_playwright_collector_and_persists_when_valid(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    called: dict[str, object] = {}

    async def fake_collect(*, silent: bool) -> dict[str, str]:
        called["silent"] = silent
        return {"reddit_session": "session-token", "csrf_token": "csrf-token"}

    async def fake_valid(_cookies: dict[str, str]) -> bool:
        return True

    monkeypatch.setattr(cookie_manager, "_collect_reddit_cookies_via_playwright", fake_collect)
    monkeypatch.setattr(cookie_manager, "check_cookies_valid", fake_valid)
    monkeypatch.setattr(cookie_manager, "_save_cookies", lambda cookies: called.setdefault("saved", cookies))
    monkeypatch.setattr(cookie_manager, "save_meta", lambda meta: called.setdefault("meta", meta))

    cookies = await cookie_manager.setup_cookies(silent=True)

    assert called.get("silent") is True
    assert called.get("saved") == cookies
    assert isinstance(called.get("meta"), dict)
    assert "cookies_created_at" in called["meta"]
    assert cookies["reddit_session"] == "session-token"


@pytest.mark.anyio
async def test_setup_cookies_does_not_persist_when_validation_fails(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    called: dict[str, object] = {}

    async def fake_collect(*, silent: bool) -> dict[str, str]:
        called["silent"] = silent
        return {"reddit_session": "invalid-token"}

    async def fake_valid(_cookies: dict[str, str]) -> bool:
        return False

    monkeypatch.setattr(cookie_manager, "_collect_reddit_cookies_via_playwright", fake_collect)
    monkeypatch.setattr(cookie_manager, "check_cookies_valid", fake_valid)
    monkeypatch.setattr(cookie_manager, "_save_cookies", lambda cookies: called.setdefault("saved", cookies))

    with pytest.raises(RuntimeError, match="validation failed"):
        await cookie_manager.setup_cookies(silent=True)

    assert called.get("silent") is True
    assert "saved" not in called


def test_filter_reddit_cookies_keeps_only_reddit_domains() -> None:
    all_cookies = [
        {"name": "reddit_session", "value": "a", "domain": ".reddit.com"},
        {"name": "csrf_token", "value": "b", "domain": "reddit.com"},
        {"name": "other", "value": "c", "domain": ".example.com"},
    ]

    result = cookie_manager._filter_reddit_cookies(all_cookies)

    assert result == {"reddit_session": "a", "csrf_token": "b"}


@pytest.mark.anyio
async def test_collect_silent_mode_never_opens_interactive_login(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    candidate = cookie_manager.BrowserProfileCandidate(
        browser_label="Google Chrome",
        executable_path=Path("."),
        user_data_dir=Path("."),
        profile_name="Profile 1",
        profile_dir=Path("."),
        cookies_db=Path("."),
        reddit_cookie_rows=2,
        cookies_mtime=123.0,
    )
    calls: list[bool] = []

    async def fake_read(
        _candidate: cookie_manager.BrowserProfileCandidate,
        *,
        interactive: bool,
        async_playwright: object,
    ) -> dict[str, str]:
        calls.append(interactive)
        return {}

    monkeypatch.setattr(cookie_manager, "_discover_browser_profile_candidates", lambda: [candidate])
    monkeypatch.setattr(cookie_manager, "_read_cookies_from_profile_copy", fake_read)

    with pytest.raises(RuntimeError, match="No reusable Reddit session found"):
        await cookie_manager._collect_reddit_cookies_via_playwright(silent=True)

    assert calls == [False]


@pytest.mark.anyio
async def test_collect_non_silent_falls_back_to_interactive_login(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    candidate = cookie_manager.BrowserProfileCandidate(
        browser_label="Google Chrome",
        executable_path=Path("."),
        user_data_dir=Path("."),
        profile_name="Profile 4",
        profile_dir=Path("."),
        cookies_db=Path("."),
        reddit_cookie_rows=0,
        cookies_mtime=456.0,
    )
    calls: list[bool] = []

    async def fake_read(
        _candidate: cookie_manager.BrowserProfileCandidate,
        *,
        interactive: bool,
        async_playwright: object,
    ) -> dict[str, str]:
        calls.append(interactive)
        if interactive:
            return {"reddit_session": "session-token"}
        return {}

    monkeypatch.setattr(cookie_manager, "_discover_browser_profile_candidates", lambda: [candidate])
    monkeypatch.setattr(cookie_manager, "_read_cookies_from_profile_copy", fake_read)

    cookies = await cookie_manager._collect_reddit_cookies_via_playwright(silent=False)
    assert cookies["reddit_session"] == "session-token"
    assert calls == [True]


@pytest.mark.anyio
async def test_collect_non_silent_errors_when_no_browser_profile_found(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    monkeypatch.setattr(cookie_manager, "_discover_browser_profile_candidates", lambda: [])

    with pytest.raises(RuntimeError, match="No compatible local Chrome/Edge profile found"):
        await cookie_manager._collect_reddit_cookies_via_playwright(silent=False)
