"""Tests para gsc_auth (sin credenciales reales ni red)."""

import os
import sys
from unittest import mock

import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))

from functions.infra.gsc_auth import gsc_auth  # noqa: E402

_SCOPE = "https://www.googleapis.com/auth/webmasters.readonly"


def _patches():
    """Devuelve los context managers para mockear creds y build.

    La funcion importa de forma diferida desde
    ``google.oauth2.service_account`` y ``googleapiclient.discovery``,
    por eso se parchea en el modulo de origen.
    """
    creds_patch = mock.patch(
        "google.oauth2.service_account.Credentials.from_service_account_file"
    )
    build_patch = mock.patch("googleapiclient.discovery.build")
    return creds_patch, build_patch


def test_build_se_llama_con_searchconsole_v1_y_cache_off():
    creds_patch, build_patch = _patches()
    with creds_patch as m_creds, build_patch as m_build:
        fake_creds = mock.Mock(name="creds")
        m_creds.return_value = fake_creds
        fake_service = mock.Mock(name="service")
        m_build.return_value = fake_service

        result = gsc_auth(credentials_path="/tmp/sa.json")

        assert result is fake_service
        m_build.assert_called_once_with(
            "searchconsole",
            "v1",
            credentials=fake_creds,
            cache_discovery=False,
        )


def test_credentials_se_cargan_con_scope_readonly():
    creds_patch, build_patch = _patches()
    with creds_patch as m_creds, build_patch as m_build:
        m_creds.return_value = mock.Mock()
        m_build.return_value = mock.Mock()

        gsc_auth(credentials_path="/tmp/sa.json")

        m_creds.assert_called_once_with("/tmp/sa.json", scopes=[_SCOPE])


def test_fallback_a_env_var_gsc_sa_json():
    creds_patch, build_patch = _patches()
    with creds_patch as m_creds, build_patch as m_build, mock.patch.dict(
        os.environ, {"GSC_SA_JSON": "/env/sa.json"}, clear=False
    ):
        m_creds.return_value = mock.Mock()
        m_build.return_value = mock.Mock()

        gsc_auth(credentials_path="")

        m_creds.assert_called_once_with("/env/sa.json", scopes=[_SCOPE])


def test_subject_aplica_with_subject():
    creds_patch, build_patch = _patches()
    with creds_patch as m_creds, build_patch as m_build:
        base_creds = mock.Mock(name="base_creds")
        delegated = mock.Mock(name="delegated_creds")
        base_creds.with_subject.return_value = delegated
        m_creds.return_value = base_creds
        m_build.return_value = mock.Mock()

        gsc_auth(credentials_path="/tmp/sa.json", subject="user@dominio.com")

        base_creds.with_subject.assert_called_once_with("user@dominio.com")
        _, kwargs = m_build.call_args
        assert kwargs["credentials"] is delegated


def test_error_cuando_falta_credential():
    creds_patch, build_patch = _patches()
    with creds_patch, build_patch, mock.patch.dict(
        os.environ, {}, clear=True
    ):
        with pytest.raises(ValueError) as exc:
            gsc_auth(credentials_path="")
        assert "GSC_SA_JSON" in str(exc.value)
