from unittest import mock

import ibis
import pydata_google_auth
import pytest
from google.auth import credentials as auth
from google.cloud import bigquery as bq

import ibis_bigquery

pytestmark = pytest.mark.bigquery


def test_repeated_project_name(project_id, credentials):
    con = ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="{}.testing".format(project_id),
        credentials=credentials,
    )
    assert "functional_alltypes" in con.list_tables()


def test_project_id_different_from_default_credentials(monkeypatch):
    creds = mock.create_autospec(auth.Credentials)

    def mock_credentials(*args, **kwargs):
        return creds, "default-project-id"

    monkeypatch.setattr(pydata_google_auth, "default", mock_credentials)
    con = ibis_bigquery.connect(project_id="explicit-project-id",)
    assert con.billing_project == "explicit-project-id"


def test_without_dataset(project_id, credentials):
    con = ibis_bigquery.connect(project_id=project_id, credentials=credentials,)
    with pytest.raises(ValueError, match="Unable to determine BigQuery"):
        con.list_tables()


def test_application_name_sets_user_agent(project_id, credentials, monkeypatch):
    mock_client = mock.create_autospec(bq.Client)
    monkeypatch.setattr(bq, "Client", mock_client)
    ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="bigquery-public-data.stackoverflow",
        application_name="my-great-app/0.7.0",
        credentials=credentials,
    )
    info = mock_client.call_args[1]["client_info"]
    user_agent = info.to_user_agent()
    assert " ibis/{}".format(ibis.__version__) in user_agent
    assert "my-great-app/0.7.0 " in user_agent


def test_auth_default(project_id, credentials, monkeypatch):
    mock_calls = []

    def mock_default(*args, **kwargs):
        mock_calls.append((args, kwargs))
        return credentials, project_id

    monkeypatch.setattr(pydata_google_auth, "default", mock_default)

    ibis_bigquery.connect(
        project_id=project_id, dataset_id="bigquery-public-data.stackoverflow",
    )

    assert len(mock_calls) == 1
    args, kwargs = mock_calls[0]
    assert len(args) == 1
    scopes = args[0]
    assert scopes == ibis_bigquery.SCOPES
    auth_local_webserver = kwargs["use_local_webserver"]
    auth_cache = kwargs["credentials_cache"]
    assert not auth_local_webserver
    assert isinstance(auth_cache, pydata_google_auth.cache.ReadWriteCredentialsCache,)


def test_auth_local_webserver(project_id, credentials, monkeypatch):
    mock_calls = []

    def mock_default(*args, **kwargs):
        mock_calls.append((args, kwargs))
        return credentials, project_id

    monkeypatch.setattr(pydata_google_auth, "default", mock_default)

    ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="bigquery-public-data.stackoverflow",
        auth_local_webserver=True,
    )

    assert len(mock_calls) == 1
    _, kwargs = mock_calls[0]
    auth_local_webserver = kwargs["use_local_webserver"]
    assert auth_local_webserver


def test_auth_external_data(project_id, credentials, monkeypatch):
    mock_calls = []

    def mock_default(*args, **kwargs):
        mock_calls.append((args, kwargs))
        return credentials, project_id

    monkeypatch.setattr(pydata_google_auth, "default", mock_default)

    ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="bigquery-public-data.stackoverflow",
        auth_external_data=True,
    )

    assert len(mock_calls) == 1
    args, _ = mock_calls[0]
    assert len(args) == 1
    scopes = args[0]
    assert scopes == ibis_bigquery.EXTERNAL_DATA_SCOPES


def test_auth_cache_reauth(project_id, credentials, monkeypatch):
    mock_calls = []

    def mock_default(*args, **kwargs):
        mock_calls.append((args, kwargs))
        return credentials, project_id

    monkeypatch.setattr(pydata_google_auth, "default", mock_default)

    ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="bigquery-public-data.stackoverflow",
        auth_cache="reauth",
    )

    assert len(mock_calls) == 1
    _, kwargs = mock_calls[0]
    auth_cache = kwargs["credentials_cache"]
    assert isinstance(auth_cache, pydata_google_auth.cache.WriteOnlyCredentialsCache,)


def test_auth_cache_none(project_id, credentials, monkeypatch):
    mock_calls = []

    def mock_default(*args, **kwargs):
        mock_calls.append((args, kwargs))
        return credentials, project_id

    monkeypatch.setattr(pydata_google_auth, "default", mock_default)

    ibis_bigquery.connect(
        project_id=project_id,
        dataset_id="bigquery-public-data.stackoverflow",
        auth_cache="none",
    )

    assert len(mock_calls) == 1
    _, kwargs = mock_calls[0]
    auth_cache = kwargs["credentials_cache"]
    assert auth_cache is pydata_google_auth.cache.NOOP


def test_auth_cache_unknown(project_id):
    with pytest.raises(ValueError, match="unexpected value for auth_cache"):
        ibis_bigquery.connect(
            project_id=project_id,
            dataset_id="bigquery-public-data.stackoverflow",
            auth_cache="not_a_real_cache",
        )
