"""Units for the Google Workspace connector (Sheets & Drive)."""

from __future__ import annotations

import uuid

import httpx
from legate.agent.tooling import ToolContext
from legate.config import get_settings
from legate.connectors.google import GoogleConnector

_SECRETS = {"client_id": "cid", "client_secret": "csecret", "refresh_token": "rtok"}


def _ctx() -> ToolContext:
    return ToolContext(workspace_id=uuid.uuid4(), settings=get_settings())


def _google_handler(captured: dict):
    def handler(request: httpx.Request) -> httpx.Response:
        url = str(request.url)
        captured["last_url"] = url
        if url.startswith("https://oauth2.googleapis.com/token"):
            captured["token_body"] = request.content.decode()
            return httpx.Response(200, json={"access_token": "ya29.test", "expires_in": 3600})
        captured.setdefault("auth", request.headers.get("authorization"))
        if "/about" in url:
            return httpx.Response(200, json={"user": {"emailAddress": "a@b.com"}})
        if ":append" in url:
            captured["append_body"] = request.content.decode()
            return httpx.Response(
                200, json={"updates": {"updatedRange": "Sheet1!A5:B5", "updatedRows": 1}}
            )
        if "/values/" in url:
            return httpx.Response(200, json={"range": "Sheet1!A1:B2", "values": [["a", "b"]]})
        if "/files/" in url:
            return httpx.Response(200, json={"id": "f1", "name": "doc", "mimeType": "text/plain"})
        if "/files" in url:
            return httpx.Response(200, json={"files": [{"id": "f1", "name": "doc"}]})
        return httpx.Response(404, json={})

    return handler


async def test_google_read_range_exchanges_token_first(set_connector_http):
    captured: dict = {}
    set_connector_http(_google_handler(captured))
    conn = GoogleConnector()
    res = await conn.execute(
        "gsheets.read_range",
        {"range": "Sheet1!A1:B2"},
        {"default_spreadsheet_id": "sheet1"},
        _SECRETS,
        _ctx(),
    )
    assert res.ok and res.data["values"] == [["a", "b"]]
    assert "grant_type=refresh_token" in captured["token_body"]
    assert captured["auth"] == "Bearer ya29.test"


async def test_google_append_row_is_write(set_connector_http):
    captured: dict = {}
    set_connector_http(_google_handler(captured))
    conn = GoogleConnector()
    res = await conn.execute(
        "gsheets.append_row",
        {"range": "Sheet1!A1", "values": ["x", "y"]},
        {"default_spreadsheet_id": "sheet1"},
        _SECRETS,
        _ctx(),
    )
    assert res.ok and res.data["updated_rows"] == 1
    assert (
        ":append" in captured["last_url"]
        and "valueInputOption=USER_ENTERED" in captured["last_url"]
    )
    assert '"values":[["x","y"]]' in captured["append_body"].replace(" ", "")


async def test_google_drive_list_and_get(set_connector_http):
    captured: dict = {}
    set_connector_http(_google_handler(captured))
    conn = GoogleConnector()
    listed = await conn.execute(
        "gdrive.list_files", {"query": "name contains 'x'"}, {}, _SECRETS, _ctx()
    )
    assert listed.ok and listed.data["files"][0]["id"] == "f1"
    got = await conn.execute("gdrive.get_file", {"file_id": "f1"}, {}, _SECRETS, _ctx())
    assert got.ok and got.data["name"] == "doc"


async def test_google_missing_spreadsheet_id(set_connector_http):
    set_connector_http(_google_handler({}))
    conn = GoogleConnector()
    res = await conn.execute("gsheets.read_range", {"range": "A1:B2"}, {}, _SECRETS, _ctx())
    assert not res.ok and "spreadsheet_id" in res.error


async def test_google_token_failure_is_reported(set_connector_http):
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(400, json={"error": "invalid_grant"})

    set_connector_http(handler)
    conn = GoogleConnector()
    res = await conn.execute("gdrive.list_files", {}, {}, _SECRETS, _ctx())
    assert not res.ok and "token" in res.error


async def test_google_test_connection(set_connector_http):
    set_connector_http(_google_handler({}))
    conn = GoogleConnector()
    check = await conn.test_connection({}, _SECRETS)
    assert check.ok
