from __future__ import annotations

import asyncio
import json
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path:
    sys.path.insert(0, str(SRC))

from fivemghost_shared_client.config_helpers import build_shared_auth_paths
from fivemghost_shared_client import TokenManager


def test_build_shared_auth_paths_resolves_first_party_auth_home(tmp_path: Path) -> None:
    paths = build_shared_auth_paths(tmp_path)

    assert paths["shared_auth_dir"] == tmp_path / ".mkterswingman"
    assert paths["shared_auth_json"] == tmp_path / ".mkterswingman" / "auth.json"


def test_token_manager_prefers_env_override(tmp_path: Path) -> None:
    auth_path = build_shared_auth_paths(tmp_path)["shared_auth_json"]
    manager = TokenManager("https://example.com", auth_json_path=auth_path, env_token_name="REDDIT_MCP_TOKEN", env={"REDDIT_MCP_TOKEN": "pat_from_env"})

    assert asyncio.run(manager.get_valid_token()) == "pat_from_env"


def test_token_manager_save_pat_writes_shared_auth(tmp_path: Path) -> None:
    auth_path = build_shared_auth_paths(tmp_path)["shared_auth_json"]
    manager = TokenManager("https://example.com", auth_json_path=auth_path, env_token_name="REDDIT_MCP_TOKEN", env={})

    asyncio.run(manager.save_pat("pat_shared_123"))

    assert json.loads(auth_path.read_text("utf-8")) == {
        "type": "pat",
        "pat": "pat_shared_123",
    }


def test_token_manager_save_tokens_writes_shared_auth(tmp_path: Path) -> None:
    auth_path = build_shared_auth_paths(tmp_path)["shared_auth_json"]
    manager = TokenManager("https://example.com", auth_json_path=auth_path, env_token_name="REDDIT_MCP_TOKEN", env={})

    asyncio.run(manager.save_tokens("access_123", "refresh_123", 3600, "client_123"))

    auth = json.loads(auth_path.read_text("utf-8"))
    assert auth["type"] == "jwt"
    assert auth["access_token"] == "access_123"
    assert auth["refresh_token"] == "refresh_123"
    assert auth["client_id"] == "client_123"
    assert isinstance(auth["expires_at"], int)


def test_token_manager_refresh_writes_back_to_shared_auth(tmp_path: Path, monkeypatch) -> None:
    auth_path = build_shared_auth_paths(tmp_path)["shared_auth_json"]
    auth_path.parent.mkdir(parents=True, exist_ok=True)
    auth_path.write_text(
        json.dumps(
            {
                "type": "jwt",
                "access_token": "expired_access",
                "refresh_token": "refresh_old",
                "expires_at": 1,
                "client_id": "client_old",
            },
            indent=2,
        ),
        "utf-8",
    )

    manager = TokenManager("https://example.com", auth_json_path=auth_path, env_token_name="REDDIT_MCP_TOKEN", env={})

    async def fake_refresh(refresh_token: str, client_id: str | None) -> dict | None:
        assert refresh_token == "refresh_old"
        assert client_id == "client_old"
        return {
            "access_token": "access_new",
            "refresh_token": "refresh_new",
            "expires_in": 7200,
        }

    monkeypatch.setattr(manager, "_refresh_tokens", fake_refresh)

    assert asyncio.run(manager.get_valid_token()) == "access_new"

    auth = json.loads(auth_path.read_text("utf-8"))
    assert auth["type"] == "jwt"
    assert auth["access_token"] == "access_new"
    assert auth["refresh_token"] == "refresh_new"
    assert auth["client_id"] == "client_old"
    assert auth["expires_at"] > 0
