# Copyright 2016 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import datetime

import mock
import pytest

from google.auth import app_engine


class _AppIdentityModule(object):
    """The interface of the App Idenity app engine module.
    See https://cloud.google.com/appengine/docs/standard/python/refdocs
    /google.appengine.api.app_identity.app_identity
    """

    def get_application_id(self):
        raise NotImplementedError()

    def sign_blob(self, bytes_to_sign, deadline=None):
        raise NotImplementedError()

    def get_service_account_name(self, deadline=None):
        raise NotImplementedError()

    def get_access_token(self, scopes, service_account_id=None):
        raise NotImplementedError()


@pytest.fixture
def app_identity(monkeypatch):
    """Mocks the app_identity module for google.auth.app_engine."""
    app_identity_module = mock.create_autospec(_AppIdentityModule, instance=True)
    monkeypatch.setattr(app_engine, "app_identity", app_identity_module)
    yield app_identity_module


def test_get_project_id(app_identity):
    app_identity.get_application_id.return_value = mock.sentinel.project
    assert app_engine.get_project_id() == mock.sentinel.project


@mock.patch.object(app_engine, "app_identity", new=None)
def test_get_project_id_missing_apis():
    with pytest.raises(EnvironmentError) as excinfo:
        assert app_engine.get_project_id()

    assert excinfo.match(r"App Engine APIs are not available")


class TestSigner(object):
    def test_key_id(self, app_identity):
        app_identity.sign_blob.return_value = (
            mock.sentinel.key_id,
            mock.sentinel.signature,
        )

        signer = app_engine.Signer()

        assert signer.key_id is None

    def test_sign(self, app_identity):
        app_identity.sign_blob.return_value = (
            mock.sentinel.key_id,
            mock.sentinel.signature,
        )

        signer = app_engine.Signer()
        to_sign = b"123"

        signature = signer.sign(to_sign)

        assert signature == mock.sentinel.signature
        app_identity.sign_blob.assert_called_with(to_sign)


class TestCredentials(object):
    @mock.patch.object(app_engine, "app_identity", new=None)
    def test_missing_apis(self):
        with pytest.raises(EnvironmentError) as excinfo:
            app_engine.Credentials()

        assert excinfo.match(r"App Engine APIs are not available")

    def test_default_state(self, app_identity):
        credentials = app_engine.Credentials()

        # Not token acquired yet
        assert not credentials.valid
        # Expiration hasn't been set yet
        assert not credentials.expired
        # Scopes are required
        assert not credentials.scopes
        assert not credentials.default_scopes
        assert credentials.requires_scopes
        assert not credentials.quota_project_id

    def test_with_scopes(self, app_identity):
        credentials = app_engine.Credentials()

        assert not credentials.scopes
        assert credentials.requires_scopes

        scoped_credentials = credentials.with_scopes(["email"])

        assert scoped_credentials.has_scopes(["email"])
        assert not scoped_credentials.requires_scopes

    def test_with_default_scopes(self, app_identity):
        credentials = app_engine.Credentials()

        assert not credentials.scopes
        assert not credentials.default_scopes
        assert credentials.requires_scopes

        scoped_credentials = credentials.with_scopes(
            scopes=None, default_scopes=["email"]
        )

        assert scoped_credentials.has_scopes(["email"])
        assert not scoped_credentials.requires_scopes

    def test_with_quota_project(self, app_identity):
        credentials = app_engine.Credentials()

        assert not credentials.scopes
        assert not credentials.quota_project_id

        quota_project_creds = credentials.with_quota_project("project-foo")

        assert quota_project_creds.quota_project_id == "project-foo"

    def test_service_account_email_implicit(self, app_identity):
        app_identity.get_service_account_name.return_value = (
            mock.sentinel.service_account_email
        )
        credentials = app_engine.Credentials()

        assert credentials.service_account_email == mock.sentinel.service_account_email
        assert app_identity.get_service_account_name.called

    def test_service_account_email_explicit(self, app_identity):
        credentials = app_engine.Credentials(
            service_account_id=mock.sentinel.service_account_email
        )

        assert credentials.service_account_email == mock.sentinel.service_account_email
        assert not app_identity.get_service_account_name.called

    @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
    def test_refresh(self, utcnow, app_identity):
        token = "token"
        ttl = 643942923
        app_identity.get_access_token.return_value = token, ttl
        credentials = app_engine.Credentials(
            scopes=["email"], default_scopes=["profile"]
        )

        credentials.refresh(None)

        app_identity.get_access_token.assert_called_with(
            credentials.scopes, credentials._service_account_id
        )
        assert credentials.token == token
        assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
        assert credentials.valid
        assert not credentials.expired

    @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
    def test_refresh_with_default_scopes(self, utcnow, app_identity):
        token = "token"
        ttl = 643942923
        app_identity.get_access_token.return_value = token, ttl
        credentials = app_engine.Credentials(default_scopes=["email"])

        credentials.refresh(None)

        app_identity.get_access_token.assert_called_with(
            credentials.default_scopes, credentials._service_account_id
        )
        assert credentials.token == token
        assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
        assert credentials.valid
        assert not credentials.expired

    def test_sign_bytes(self, app_identity):
        app_identity.sign_blob.return_value = (
            mock.sentinel.key_id,
            mock.sentinel.signature,
        )
        credentials = app_engine.Credentials()
        to_sign = b"123"

        signature = credentials.sign_bytes(to_sign)

        assert signature == mock.sentinel.signature
        app_identity.sign_blob.assert_called_with(to_sign)

    def test_signer(self, app_identity):
        credentials = app_engine.Credentials()
        assert isinstance(credentials.signer, app_engine.Signer)

    def test_signer_email(self, app_identity):
        credentials = app_engine.Credentials()
        assert credentials.signer_email == credentials.service_account_email
