import json
import configparser
from pathlib import Path

import pytest

import project_hub.gitlab.auth as auth_module
from project_hub.gitlab.auth import resolve_token, store_token, auth_status


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _write_auth_json(path: Path, data: dict) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data))


def _write_python_gitlab_cfg(path: Path, sections: dict) -> None:
    """Write a .python-gitlab.cfg style INI file."""
    cfg = configparser.ConfigParser()
    for section, values in sections.items():
        cfg[section] = values
    with open(path, "w") as f:
        cfg.write(f)


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------

def test_resolve_token_from_auth_json(tmp_path, monkeypatch):
    auth_file = tmp_path / "auth.json"
    _write_auth_json(auth_file, {"gitlab.com": "token-from-file"})
    monkeypatch.setattr(auth_module, "AUTH_FILE", auth_file)
    monkeypatch.delenv("GITLAB_TOKEN", raising=False)

    assert resolve_token("gitlab.com") == "token-from-file"


def test_resolve_token_from_env(tmp_path, monkeypatch):
    # No auth.json — ensure AUTH_FILE points somewhere that doesn't exist
    monkeypatch.setattr(auth_module, "AUTH_FILE", tmp_path / "nonexistent.json")
    monkeypatch.setenv("GITLAB_TOKEN", "env-token")
    # Redirect python-gitlab.cfg so it doesn't accidentally exist
    monkeypatch.setattr(auth_module, "PYTHON_GITLAB_CFG", tmp_path / "no-cfg")

    assert resolve_token("gitlab.com") == "env-token"


def test_resolve_token_env_only_for_gitlab_com(tmp_path, monkeypatch):
    monkeypatch.setattr(auth_module, "AUTH_FILE", tmp_path / "nonexistent.json")
    monkeypatch.setenv("GITLAB_TOKEN", "env-token")
    monkeypatch.setattr(auth_module, "PYTHON_GITLAB_CFG", tmp_path / "no-cfg")

    # GITLAB_TOKEN should NOT be used for other instances
    assert resolve_token("gitlab.example.com") is None


def test_resolve_token_from_python_gitlab_cfg(tmp_path, monkeypatch):
    monkeypatch.setattr(auth_module, "AUTH_FILE", tmp_path / "nonexistent.json")
    monkeypatch.delenv("GITLAB_TOKEN", raising=False)

    cfg_path = tmp_path / ".python-gitlab.cfg"
    _write_python_gitlab_cfg(cfg_path, {
        "global": {"default": "myinstance"},
        "myinstance": {"url": "https://gitlab.example.com", "private_token": "cfg-token"},
    })
    monkeypatch.setattr(auth_module, "PYTHON_GITLAB_CFG", cfg_path)

    assert resolve_token("gitlab.example.com") == "cfg-token"


def test_store_token(tmp_path, monkeypatch):
    auth_file = tmp_path / "subdir" / "auth.json"
    monkeypatch.setattr(auth_module, "AUTH_FILE", auth_file)

    store_token("gitlab.com", "my-new-token")

    data = json.loads(auth_file.read_text())
    assert data == {"gitlab.com": "my-new-token"}


def test_store_token_merges(tmp_path, monkeypatch):
    auth_file = tmp_path / "auth.json"
    _write_auth_json(auth_file, {"other.instance.com": "existing-token"})
    monkeypatch.setattr(auth_module, "AUTH_FILE", auth_file)

    store_token("gitlab.com", "new-token")

    data = json.loads(auth_file.read_text())
    assert data["other.instance.com"] == "existing-token"
    assert data["gitlab.com"] == "new-token"


def test_auth_status_returns_instances(tmp_path, monkeypatch):
    auth_file = tmp_path / "auth.json"
    _write_auth_json(auth_file, {
        "gitlab.com": "token-a",
        "gitlab.mycompany.com": "token-b",
    })
    monkeypatch.setattr(auth_module, "AUTH_FILE", auth_file)

    results = auth_status()

    assert len(results) == 2
    instances = {r.instance for r in results}
    assert instances == {"gitlab.com", "gitlab.mycompany.com"}
    for r in results:
        assert r.token is not None
        assert r.authenticated is True
