# ========= 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. =========

from collections.abc import Callable
from dataclasses import dataclass

from mirage.core.google.client import (TokenManager, calendar_base, docs_base,
                                       drive_base, forms_base, gmail_base,
                                       sheets_base, slides_base)

# The official gws CLI generates one command per Discovery method and
# speaks raw API resources: `--params` carries path/query parameters,
# `--json` the request body, and the output is the API response JSON.
# Each entry here is one such passthrough method; the bespoke verbs
# (sheets read/write/append, docs write, the gmail helpers) stay
# hand-written beside them in the tree.


@dataclass(frozen=True, slots=True)
class GwsMethod:
    service: str
    resource: str
    method: str
    http: str
    path: str
    needs_body: bool = False
    raw_bytes: bool = False
    # Where a newly created file lands when the installation is scoped to a
    # folder. "parents" means the request body takes a parents array, so the
    # scope is filled in there. "relocate" means the API has no parents
    # field at all (the editors' create methods), so the new file is moved
    # afterwards with a Drive update. None means the method creates nothing.
    placement: str | None = None
    # Response key holding the new file's id, for "relocate".
    id_field: str = "id"


GWS_METHODS: tuple[GwsMethod, ...] = (
    GwsMethod("docs", "documents", "get", "GET", "/documents/{documentId}"),
    GwsMethod("docs",
              "documents",
              "create",
              "POST",
              "/documents",
              needs_body=True,
              placement="relocate",
              id_field="documentId"),
    GwsMethod("docs",
              "documents",
              "batchUpdate",
              "POST",
              "/documents/{documentId}:batchUpdate",
              needs_body=True),
    GwsMethod("sheets", "spreadsheets", "get", "GET",
              "/spreadsheets/{spreadsheetId}"),
    GwsMethod("sheets",
              "spreadsheets",
              "create",
              "POST",
              "/spreadsheets",
              needs_body=True,
              placement="relocate",
              id_field="spreadsheetId"),
    GwsMethod("sheets",
              "spreadsheets",
              "batchUpdate",
              "POST",
              "/spreadsheets/{spreadsheetId}:batchUpdate",
              needs_body=True),
    GwsMethod("slides", "presentations", "get", "GET",
              "/presentations/{presentationId}"),
    GwsMethod("slides",
              "presentations",
              "create",
              "POST",
              "/presentations",
              needs_body=True,
              placement="relocate",
              id_field="presentationId"),
    GwsMethod("slides",
              "presentations",
              "batchUpdate",
              "POST",
              "/presentations/{presentationId}:batchUpdate",
              needs_body=True),
    GwsMethod("drive", "files", "list", "GET", "/files"),
    GwsMethod("drive", "files", "get", "GET", "/files/{fileId}"),
    GwsMethod("drive",
              "files",
              "create",
              "POST",
              "/files",
              needs_body=True,
              placement="parents"),
    GwsMethod("drive",
              "files",
              "update",
              "PATCH",
              "/files/{fileId}",
              needs_body=True),
    GwsMethod("drive",
              "files",
              "copy",
              "POST",
              "/files/{fileId}/copy",
              placement="parents"),
    GwsMethod("drive", "files", "delete", "DELETE", "/files/{fileId}"),
    GwsMethod("drive",
              "files",
              "export",
              "GET",
              "/files/{fileId}/export",
              raw_bytes=True),
    GwsMethod("drive",
              "permissions",
              "create",
              "POST",
              "/files/{fileId}/permissions",
              needs_body=True),
    GwsMethod("drive", "permissions", "list", "GET",
              "/files/{fileId}/permissions"),
    GwsMethod("drive", "permissions", "delete", "DELETE",
              "/files/{fileId}/permissions/{permissionId}"),
    GwsMethod("gmail", "users labels", "list", "GET",
              "/users/{userId}/labels"),
    GwsMethod("gmail", "users messages", "list", "GET",
              "/users/{userId}/messages"),
    GwsMethod("gmail", "users messages", "get", "GET",
              "/users/{userId}/messages/{id}"),
    GwsMethod("gmail",
              "users messages",
              "send",
              "POST",
              "/users/{userId}/messages/send",
              needs_body=True),
    GwsMethod("gmail", "users messages", "trash", "POST",
              "/users/{userId}/messages/{id}/trash"),
    GwsMethod("gmail", "users messages attachments", "get", "GET",
              "/users/{userId}/messages/{messageId}/attachments/{id}"),
    GwsMethod("calendar", "calendarList", "list", "GET",
              "/users/me/calendarList"),
    GwsMethod("calendar", "calendars", "get", "GET",
              "/calendars/{calendarId}"),
    GwsMethod("calendar", "events", "list", "GET",
              "/calendars/{calendarId}/events"),
    GwsMethod("calendar", "events", "get", "GET",
              "/calendars/{calendarId}/events/{eventId}"),
    GwsMethod("calendar",
              "events",
              "insert",
              "POST",
              "/calendars/{calendarId}/events",
              needs_body=True),
    GwsMethod("calendar",
              "events",
              "patch",
              "PATCH",
              "/calendars/{calendarId}/events/{eventId}",
              needs_body=True),
    GwsMethod("calendar", "events", "delete", "DELETE",
              "/calendars/{calendarId}/events/{eventId}"),
    GwsMethod("calendar",
              "freebusy",
              "query",
              "POST",
              "/freeBusy",
              needs_body=True),
    GwsMethod("forms",
              "forms",
              "create",
              "POST",
              "/forms",
              needs_body=True,
              placement="relocate",
              id_field="formId"),
    GwsMethod("forms", "forms", "get", "GET", "/forms/{formId}"),
    GwsMethod("forms",
              "forms",
              "batchUpdate",
              "POST",
              "/forms/{formId}:batchUpdate",
              needs_body=True),
    GwsMethod("forms", "forms responses", "list", "GET",
              "/forms/{formId}/responses"),
    GwsMethod("forms", "forms responses", "get", "GET",
              "/forms/{formId}/responses/{responseId}"),
)


def gws_method_description(method: "GwsMethod") -> str:
    """Render the one-line help description for a passthrough method.

    Args:
        method (GwsMethod): the Discovery method being wrapped.
    """
    return (f"{method.http} {method.path} "
            f"(Google {method.service} API passthrough)")


SERVICE_BASES: dict[str, Callable[[TokenManager], str]] = {
    "drive": drive_base,
    "docs": docs_base,
    "sheets": sheets_base,
    "slides": slides_base,
    "gmail": gmail_base,
    "calendar": calendar_base,
    "forms": forms_base,
}
