# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# 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.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========

import pytest
from aioresponses import aioresponses
from yarl import URL

from mirage.core.google.client import refresh_access_token
from mirage.core.google.config import GoogleConfig
from mirage.core.google.constants import TOKEN_URL
from mirage.resource.gdocs.config import GDocsConfig
from mirage.resource.gdrive.config import GoogleDriveConfig
from mirage.resource.secrets import reveal_secret


def test_google_config_creation():
    config = GoogleConfig(
        client_id="id",
        client_secret="secret",
        refresh_token="token",
    )
    assert config.client_id == "id"
    assert reveal_secret(config.client_secret) == "secret"
    assert reveal_secret(config.refresh_token) == "token"


def test_google_config_omits_client_secret_for_pkce():
    # Browser PKCE flows construct GoogleConfig without a secret.
    config = GoogleConfig(client_id="id", refresh_token="token")
    assert config.client_id == "id"
    assert config.client_secret is None
    assert reveal_secret(config.refresh_token) == "token"


@pytest.mark.asyncio
async def test_refresh_access_token_omits_client_secret_when_absent():
    # PKCE clients refresh with just (client_id, refresh_token, grant_type).
    # Sending an empty/None client_secret would be rejected by Google's
    # token endpoint for public clients, so make sure we don't include it.
    with aioresponses() as m:
        m.post(TOKEN_URL, payload={"access_token": "atk", "expires_in": 3600})
        config = GoogleConfig(client_id="id", refresh_token="rt")
        token, expires = await refresh_access_token(config)
        sent = m.requests[("POST", URL(TOKEN_URL))][0].kwargs
    assert token == "atk"
    assert expires == 3600
    assert "client_secret" not in sent["data"]
    assert sent["data"]["client_id"] == "id"
    assert sent["data"]["refresh_token"] == "rt"


@pytest.mark.asyncio
async def test_refresh_access_token_includes_client_secret_when_present():
    # Backwards compat: Node-style configs with a real secret keep working.
    with aioresponses() as m:
        m.post(TOKEN_URL, payload={"access_token": "atk", "expires_in": 3600})
        config = GoogleConfig(
            client_id="id",
            client_secret="secret",
            refresh_token="rt",
        )
        await refresh_access_token(config)
        sent = m.requests[("POST", URL(TOKEN_URL))][0].kwargs
    assert sent["data"]["client_secret"] == "secret"


def test_google_config_inherited_by_docs():
    config = GDocsConfig(
        client_id="id",
        client_secret="secret",
        refresh_token="token",
    )
    assert isinstance(config, GoogleConfig)
    assert config.client_id == "id"


def test_google_config_inherited_by_drive():
    config = GoogleDriveConfig(
        client_id="id",
        client_secret="secret",
        refresh_token="token",
    )
    assert isinstance(config, GoogleConfig)
    assert config.client_id == "id"
