"""Arcade Starter Tools for Zoho Creator

DO NOT EDIT THIS MODULE DIRECTLY.

THIS MODULE WAS AUTO-GENERATED BY TRANSPILING THE API STARTER TOOL JSON DEFINITIONS
IN THE ../wrapper_tools DIRECTORY INTO PYTHON CODE. ANY CHANGES TO THIS MODULE WILL
BE OVERWRITTEN BY THE TRANSPILER.
"""

import asyncio
import json
from enum import Enum
from typing import Annotated, Any

import httpx
import jsonschema
from arcade_tdk import ToolContext, tool
from arcade_tdk.auth import OAuth2
from arcade_tdk.errors import RetryableToolError

from .request_body_schemas import REQUEST_BODY_SCHEMAS

# Retry configuration
INITIAL_RETRY_DELAY = 0.5  # seconds

HTTP_CLIENT = httpx.AsyncClient(
    timeout=httpx.Timeout(60.0, connect=10.0),
    limits=httpx.Limits(max_keepalive_connections=20, max_connections=100),
    transport=httpx.AsyncHTTPTransport(retries=3),
    http2=True,
    follow_redirects=True,
)


class ToolMode(str, Enum):
    """Mode for tools with complex request bodies."""

    GET_REQUEST_SCHEMA = "get_request_schema"
    EXECUTE = "execute"


def remove_none_values(data: dict[str, Any]) -> dict[str, Any]:
    return {k: v for k, v in data.items() if v is not None}


async def make_request(
    url: str,
    method: str,
    params: dict[str, Any] | None = None,
    headers: dict[str, Any] | None = None,
    data: str | None = None,
    max_retries: int = 3,
) -> httpx.Response:
    """Make an HTTP request with retry logic for 5xx server errors."""
    for attempt in range(max_retries):
        try:
            response = await HTTP_CLIENT.request(
                url=url,
                method=method,
                params=params,
                headers=headers,
                data=data,  # type: ignore[arg-type]
            )
            response.raise_for_status()
        except httpx.HTTPStatusError as e:
            # Only retry on 5xx server errors
            if e.response.status_code >= 500 and attempt < max_retries - 1:
                # Exponential backoff: 0.5s, 1s, 2s
                await asyncio.sleep(INITIAL_RETRY_DELAY * (2**attempt))
                continue
            # Re-raise for 4xx errors or if max retries reached
            raise
        except httpx.RequestError:
            # Don't retry request errors (network issues are handled by transport)
            raise
        else:
            return response

    # This should never be reached, but satisfies type checker
    raise httpx.RequestError("Max retries exceeded")  # noqa: TRY003


def validate_json_against_schema(
    json_data: dict[str, Any], schema: dict[str, Any]
) -> tuple[bool, str | None]:
    """Validate JSON data against an OpenAPI/JSON Schema.

    This provides full JSON Schema Draft 7 validation including:
    - Required fields, types, enums
    - Pattern validation (regex)
    - Format validation (email, uuid, date-time, etc.)
    - Min/max length and values
    - oneOf, anyOf, allOf
    - And all other JSON Schema features

    Args:
        json_data: The JSON data to validate
        schema: The JSON Schema to validate against

    Returns:
        Tuple of (is_valid, error_messages). If valid, error_messages is None.
        If invalid, error_messages contains all validation errors.
    """
    try:
        validator = jsonschema.Draft7Validator(
            schema, format_checker=jsonschema.Draft7Validator.FORMAT_CHECKER
        )
        # Collect ALL validation errors
        errors = list(validator.iter_errors(json_data))
        if errors:
            # Format all errors with their paths
            error_messages = []
            for error in errors:
                error_path = ".".join(str(p) for p in error.path) if error.path else "root"
                error_messages.append(f"{error.message} at {error_path}")
            # Join all errors with newlines
            return False, "\n".join(error_messages)
        else:
            return True, None
    except jsonschema.SchemaError as e:
        return False, f"Invalid schema: {e.message}"
    except Exception as e:
        return False, f"Validation error: {e!s}"


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.meta.application.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_app_sections(
    context: ToolContext,
    zoho_account_owner_name: Annotated[
        str,
        "The account owner's username in Zoho. Required to fetch data for the specified application.",  # noqa: E501
    ],
    zoho_application_link_name: Annotated[
        str,
        "The unique link name of the Zoho Creator application whose sections and components you want to fetch.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetch details of sections and components in Zoho Creator apps.

    Use this tool to retrieve information about the sections, forms, reports, and pages of a Zoho Creator application's web form factor."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/{app_link_name}/sections".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=zoho_application_link_name,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_auth=OAuth2(id="arcade-zoho"), requires_secrets=["ZOHO_SERVER_URL"])
async def fetch_record_detail(
    context: ToolContext,
    application_private_link: Annotated[
        str,
        "The private link identifier of the Zoho application, necessary for accessing the specific record's detail view.",  # noqa: E501
    ],
    account_owner_name: Annotated[
        str,
        "The name of the account owner in Zoho. This specifies the owner of the account to which the app belongs.",  # noqa: E501
    ],
    application_link_name: Annotated[
        str,
        "The unique identifier or slug for the specific Zoho app to query. This determines which app's data is accessed.",  # noqa: E501
    ],
    report_link_name: Annotated[
        str,
        "The link name of the report from which to fetch the record detail. It identifies the specific report in the Zoho app.",  # noqa: E501
    ],
    record_id: Annotated[
        str,
        "The unique identifier of the record to fetch detailed information for. It should be a string corresponding to the record's ID in the Zoho app.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches detailed view data of a record by ID.

    Use this tool to fetch detailed information of a specific record identified by its ID in a Zoho app. It does not include related data blocks."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/publish/{account_owner_name}/{app_link_name}/report/{report_link_name}/{record_ID}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
            record_ID=record_id,
        ),
        method="GET",
        params=remove_none_values({"privatelink": application_private_link}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.meta.form.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_form_fields_metadata(
    context: ToolContext,
    account_owner_name: Annotated[
        str,
        "The Zoho account owner's username. Required to identify the specific account that owns the application.",  # noqa: E501
    ],
    application_link_name: Annotated[
        str,
        "The unique link name of the Zoho Creator application. It identifies which application's form metadata to fetch.",  # noqa: E501
    ],
    form_identifier: Annotated[
        str, "The unique identifier or link name of the Zoho Creator form to fetch metadata for."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches metadata of fields in a Zoho Creator form.

    Use this tool to obtain meta information about all the fields within a specified form in a Zoho Creator application. It should be called when you need to understand the structure or details of the form fields such as field types, names, etc."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/{app_link_name}/form/{form_link_name}/fields".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            form_link_name=form_identifier,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.meta.application.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_reports_meta(
    context: ToolContext,
    zoho_account_owner_name: Annotated[
        str,
        "The name of the account owner in Zoho. Used to identify which account's report metadata to fetch.",  # noqa: E501
    ],
    zoho_app_link_name: Annotated[
        str,
        "The unique link name of the Zoho Creator application to fetch report metadata from. This identifies the specific app within your Zoho account.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches meta information of reports in Zoho Creator.

    This tool retrieves the meta information for all reports within a specified Zoho Creator application. Use it to gain insights into the report configurations and structures available in a particular app."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/{app_link_name}/reports".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=zoho_app_link_name,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.UPDATE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def update_zoho_creator_report_records(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    account_owner_name: Annotated[
        str | None,
        "The username of the owner of the Zoho account associated with the application. Required for determining access and permissions.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique identifier (link name) of the Zoho Creator application. Required to specify the target app for updating records.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    report_link_name: Annotated[
        str | None,
        "The name or identifier of the report in Zoho Creator whose records you want to update.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    process_until_limit_enabled: Annotated[
        bool | None,
        "Set to true to process records until reaching a limit of 200.  Only used when mode is 'execute'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Update records in a Zoho Creator report.

    Use this tool to update up to 200 records in a specific report of a Zoho Creator application, ensuring compliance with data validation.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path, query parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path, query parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS[
                "UPDATEZOHOCREATORREPORTRECORDS_REQUEST_BODY_SCHEMA"
            ],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path, query parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: account_owner_name
    if not account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'account_owner_name' validation failed. "
            f"Received: {account_owner_name}",
            additional_prompt_content=(
                "The 'account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: report_link_name
    if not report_link_name:
        raise RetryableToolError(
            message="Invalid or missing report_link_name parameter",
            developer_message=f"Path parameter "
            f"'report_link_name' validation failed. "
            f"Received: {report_link_name}",
            additional_prompt_content=(
                "The 'report_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "report_link_name value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["UPDATEZOHOCREATORREPORTRECORDS_REQUEST_BODY_SCHEMA"],
                    indent=2,
                )
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["UPDATEZOHOCREATORREPORTRECORDS_REQUEST_BODY_SCHEMA"],
                    indent=2,
                )
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["UPDATEZOHOCREATORREPORTRECORDS_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['UPDATEZOHOCREATORREPORTRECORDS_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
        ),
        method="PATCH",
        params=remove_none_values({"process_until_limit": process_until_limit_enabled}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_records(
    context: ToolContext,
    account_owner_identifier: Annotated[
        str, "The unique identifier for the Zoho account owner. Required to fetch the report data."
    ],
    application_link_name: Annotated[
        str,
        "The unique identifier for the Zoho Creator application. It specifies which app's report to fetch.",  # noqa: E501
    ],
    report_link_name: Annotated[
        str, "The unique link name of the Zoho Creator report to fetch records from."
    ],
    start_record_index: Annotated[
        int | None, "The starting index of records to retrieve from the report. Must be an integer."
    ] = None,
    record_limit: Annotated[
        int | None, "The maximum number of records to retrieve, up to 200."
    ] = None,
    filter_criteria: Annotated[
        str | None,
        "Specify conditions to filter records. Use Zoho Creator query format for filtering.",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetch records from a Zoho Creator report.

    Use this tool to retrieve up to 200 records from the quick view fields of a specified Zoho Creator report."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_identifier,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
        ),
        method="GET",
        params=remove_none_values({
            "from": start_record_index,
            "limit": record_limit,
            "criteria": filter_criteria,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.DELETE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def delete_report_records(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    account_owner_name: Annotated[
        str | None,
        "The name of the Zoho account owner. It identifies whose account the deletion should occur under.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique identifier for the application within Zoho Creator.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    report_identifier: Annotated[
        str | None,
        "The name of the report from which records should be deleted. Must match the link name configured in Zoho Creator.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    process_records_up_to_limit: Annotated[
        bool | None,
        "Boolean to enable processing records up to the 200-record limit per request.  Only used when mode is 'execute'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Delete records from a specified Zoho Creator report.

    Use this tool to delete up to 200 records from a specified report in your Zoho Creator application. This action will adhere to any custom validations configured for the target form.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path, query parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path, query parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["DELETEREPORTRECORDS_REQUEST_BODY_SCHEMA"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path, query parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: account_owner_name
    if not account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'account_owner_name' validation failed. "
            f"Received: {account_owner_name}",
            additional_prompt_content=(
                "The 'account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: report_identifier
    if not report_identifier:
        raise RetryableToolError(
            message="Invalid or missing report_identifier parameter",
            developer_message=f"Path parameter "
            f"'report_identifier' validation failed. "
            f"Received: {report_identifier}",
            additional_prompt_content=(
                "The 'report_identifier' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "report_identifier value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["DELETEREPORTRECORDS_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["DELETEREPORTRECORDS_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["DELETEREPORTRECORDS_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['DELETEREPORTRECORDS_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_identifier,
        ),
        method="DELETE",
        params=remove_none_values({"process_until_limit": process_records_up_to_limit}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.meta.application.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_creator_pages_meta(
    context: ToolContext,
    account_owner_name: Annotated[
        str,
        "The name of the account owner in Zoho. This identifies the owner of the application for which the page metadata is fetched.",  # noqa: E501
    ],
    zoho_app_link_name: Annotated[
        str, "The unique identifier for the Zoho Creator application to fetch page metadata."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches meta information of pages in a Zoho Creator app.

    This tool retrieves the meta information of all the pages present in a specified Zoho Creator application. Use it to gather detailed metadata about the app's pages, which can aid in app management and analysis."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/{app_link_name}/pages".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=zoho_app_link_name,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.dashboard.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def get_application_meta_info(
    context: ToolContext,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches meta information of accessible applications.

    Use this tool to retrieve the meta information of all applications you have access to in Zoho."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/applications".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL")
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.form.CREATE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def insert_records_in_zoho_form(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    zoho_account_owner_name: Annotated[
        str | None,
        "The name of the account owner in Zoho. This is required to identify which account the records should be added to.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique identifier of the application in which the form is located. This is necessary to specify the target Zoho Creator application.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    form_link_name: Annotated[
        str | None,
        "The unique link name of the form in Zoho Creator where records will be added.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Add records to a form in Zoho Creator.

    Use this tool to add one or more records to a specified form in your Zoho Creator application. It allows up to 200 records per request, subject to validation.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS[
                "INSERTRECORDSINZOHOFORM_REQUEST_BODY_SCHEMA"
            ],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: zoho_account_owner_name
    if not zoho_account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing zoho_account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'zoho_account_owner_name' validation failed. "
            f"Received: {zoho_account_owner_name}",
            additional_prompt_content=(
                "The 'zoho_account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "zoho_account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: form_link_name
    if not form_link_name:
        raise RetryableToolError(
            message="Invalid or missing form_link_name parameter",
            developer_message=f"Path parameter "
            f"'form_link_name' validation failed. "
            f"Received: {form_link_name}",
            additional_prompt_content=(
                "The 'form_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "form_link_name value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["INSERTRECORDSINZOHOFORM_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["INSERTRECORDSINZOHOFORM_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["INSERTRECORDSINZOHOFORM_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['INSERTRECORDSINZOHOFORM_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/form/{form_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=application_link_name,
            form_link_name=form_link_name,
        ),
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.UPDATE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def update_zoho_record(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    zoho_account_owner_name: Annotated[
        str | None,
        "The account owner's name in Zoho. Used to identify the correct Zoho Creator account for the update operation.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique name of the Zoho Creator application where the record resides.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    report_link_name: Annotated[
        str | None,
        "The string identifier of the report in Zoho Creator where the record is located.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    record_id: Annotated[
        str | None,
        "The unique identifier for the record to be updated in Zoho Creator. This ID specifies which record in the report will be modified.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Update a specific record in Zoho Creator by ID.

    Use this tool to update a specific record within a Zoho Creator application. This tool is useful when modifications are needed on existing entries identified by their record ID, and respects the data validations configured for the form.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["UPDATEZOHORECORD_REQUEST_BODY_SCHEMA"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: zoho_account_owner_name
    if not zoho_account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing zoho_account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'zoho_account_owner_name' validation failed. "
            f"Received: {zoho_account_owner_name}",
            additional_prompt_content=(
                "The 'zoho_account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "zoho_account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: report_link_name
    if not report_link_name:
        raise RetryableToolError(
            message="Invalid or missing report_link_name parameter",
            developer_message=f"Path parameter "
            f"'report_link_name' validation failed. "
            f"Received: {report_link_name}",
            additional_prompt_content=(
                "The 'report_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "report_link_name value."
            ),
        )

    # Validate required path parameter: record_id
    if not record_id:
        raise RetryableToolError(
            message="Invalid or missing record_id parameter",
            developer_message=f"Path parameter "
            f"'record_id' validation failed. "
            f"Received: {record_id}",
            additional_prompt_content=(
                "The 'record_id' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "record_id value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(REQUEST_BODY_SCHEMAS["UPDATEZOHORECORD_REQUEST_BODY_SCHEMA"], indent=2)
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(REQUEST_BODY_SCHEMAS["UPDATEZOHORECORD_REQUEST_BODY_SCHEMA"], indent=2)
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["UPDATEZOHORECORD_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['UPDATEZOHORECORD_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}/{record_ID}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
            record_ID=record_id,
        ),
        method="PATCH",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_record_detail(
    context: ToolContext,
    account_owner_name: Annotated[
        str,
        "The name of the account owner in Zoho to fetch the record for. This identifies the specific account under which the record exists.",  # noqa: E501
    ],
    application_identifier: Annotated[
        str,
        "The name of the application in Zoho used to uniquely identify which app's record details are to be fetched.",  # noqa: E501
    ],
    report_link_name: Annotated[
        str, "The specific name of the report in Zoho from which the data will be fetched."
    ],
    record_id: Annotated[
        str, "The unique ID of the Zoho record to fetch its detailed information."
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetches detailed view data of a Zoho record by ID.

    Use this tool to fetch the detailed information of a specific record in Zoho, identified by its record ID. This tool does not retrieve related records, only the detailed view of the specific identified record."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}/{record_ID}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_identifier,
            report_link_name=report_link_name,
            record_ID=record_id,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.report.DELETE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def delete_zoho_record(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    zoho_account_owner_name: Annotated[
        str | None,
        "The account owner's name in Zoho. Required to specify which user's account to access.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique identifier for the Zoho Creator application. Provide this to specify which application contains the record to delete.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    report_link_name: Annotated[
        str | None,
        "The unique name of the report in Zoho where the record is listed. This identifies which report contains the record to be deleted.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    record_id: Annotated[
        str | None,
        "The unique ID of the record to be deleted from Zoho Creator. This must match the ID displayed in the relevant Zoho report.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Delete a specific record in Zoho Creator by ID.

    This tool deletes a specific record in Zoho Creator using its ID. It is used when a user wants to remove a record that appears in a report. The deletion follows custom validations set for the form.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["DELETEZOHORECORD_REQUEST_BODY_SCHEMA"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: zoho_account_owner_name
    if not zoho_account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing zoho_account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'zoho_account_owner_name' validation failed. "
            f"Received: {zoho_account_owner_name}",
            additional_prompt_content=(
                "The 'zoho_account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "zoho_account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: report_link_name
    if not report_link_name:
        raise RetryableToolError(
            message="Invalid or missing report_link_name parameter",
            developer_message=f"Path parameter "
            f"'report_link_name' validation failed. "
            f"Received: {report_link_name}",
            additional_prompt_content=(
                "The 'report_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "report_link_name value."
            ),
        )

    # Validate required path parameter: record_id
    if not record_id:
        raise RetryableToolError(
            message="Invalid or missing record_id parameter",
            developer_message=f"Path parameter "
            f"'record_id' validation failed. "
            f"Received: {record_id}",
            additional_prompt_content=(
                "The 'record_id' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "record_id value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(REQUEST_BODY_SCHEMAS["DELETEZOHORECORD_REQUEST_BODY_SCHEMA"], indent=2)
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(REQUEST_BODY_SCHEMAS["DELETEZOHORECORD_REQUEST_BODY_SCHEMA"], indent=2)
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["DELETEZOHORECORD_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['DELETEZOHORECORD_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/data/{account_owner_name}/{app_link_name}/report/{report_link_name}/{record_ID}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
            record_ID=record_id,
        ),
        method="DELETE",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.bulk.CREATE"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def create_bulk_read_job(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    account_owner_name: Annotated[
        str | None,
        "The name of the account owner in Zoho for whom the bulk read job is being created. This should match the official account details.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The name of the application within Zoho to export records from.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    report_reference_name: Annotated[
        str | None,
        "Specifies the unique link or name of the report from which records will be exported in Zoho.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Initiate a bulk read job to export records.

    Use this tool to create a bulk read job in Zoho, which allows you to export records from a specified report. This is useful for managing large datasets efficiently.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["CREATEBULKREADJOB_REQUEST_BODY_SCHEMA"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required path parameter: account_owner_name
    if not account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'account_owner_name' validation failed. "
            f"Received: {account_owner_name}",
            additional_prompt_content=(
                "The 'account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: report_reference_name
    if not report_reference_name:
        raise RetryableToolError(
            message="Invalid or missing report_reference_name parameter",
            developer_message=f"Path parameter "
            f"'report_reference_name' validation failed. "
            f"Received: {report_reference_name}",
            additional_prompt_content=(
                "The 'report_reference_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "report_reference_name value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["CREATEBULKREADJOB_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["CREATEBULKREADJOB_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["CREATEBULKREADJOB_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['CREATEBULKREADJOB_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/bulk/{account_owner_name}/{app_link_name}/report/{report_link_name}/read".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_reference_name,
        ),
        method="POST",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_auth=OAuth2(id="arcade-zoho"), requires_secrets=["ZOHO_SERVER_URL"])
async def fetch_zoho_report_records(
    context: ToolContext,
    zoho_private_link: Annotated[
        str, "The private link URL or identifier for accessing a specific Zoho Creator report."
    ],
    account_owner_name: Annotated[
        str,
        "The username of the Zoho account owner. Required to identify the correct account for fetching report records.",  # noqa: E501
    ],
    zoho_application_link_name: Annotated[
        str,
        "The unique link name of the Zoho Creator application from which to fetch report records.",
    ],
    report_link_name: Annotated[
        str,
        "The unique link name of the Zoho report to fetch records from. It's required to specify which report to access.",  # noqa: E501
    ],
    record_fetch_start_index: Annotated[
        int | None, "Specify the starting index for records to be fetched. Use an integer value."
    ] = None,
    record_limit: Annotated[
        int | None, "Specify the maximum number of records to fetch, up to 200."
    ] = None,
    filter_criteria: Annotated[
        str | None,
        "A string to filter records based on specific conditions, formatted as 'Field_Name Operator Value'.",  # noqa: E501
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetch records displayed by a Zoho Creator report.

    Use this tool to retrieve up to 200 records from a Zoho Creator report. It accesses the data in the fields shown in the report's quick view."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/publish/{account_owner_name}/{app_link_name}/report/{report_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=zoho_application_link_name,
            report_link_name=report_link_name,
        ),
        method="GET",
        params=remove_none_values({
            "privatelink": zoho_private_link,
            "from": record_fetch_start_index,
            "limit": record_limit,
            "criteria": filter_criteria,
        }),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.bulk.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def get_bulk_read_job_details(
    context: ToolContext,
    account_owner_name: Annotated[
        str, "The name of the account owner in Zoho. Required for identifying the correct account."
    ],
    application_link_name: Annotated[
        str,
        "The name of the Zoho Creator application. Used to identify which application's bulk read job details are being retrieved.",  # noqa: E501
    ],
    report_link_name: Annotated[
        str,
        "The link name of the report for which the bulk read job details are requested. This is required to specify the report in Zoho Creator.",  # noqa: E501
    ],
    job_id: Annotated[
        str,
        "The unique identifier for the bulk read job to retrieve details for. This should be a string value.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Retrieve details of a completed bulk read job in Zoho Creator.

    This tool retrieves information about a bulk read job that was executed previously in Zoho Creator. It is useful when you need to check the status or outcome of a specific bulk read job."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/bulk/{account_owner_name}/{app_link_name}/report/{report_link_name}/read/{job_ID}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=account_owner_name,
            app_link_name=application_link_name,
            report_link_name=report_link_name,
            job_ID=job_id,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.dashboard.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_workspace_app_meta(
    context: ToolContext,
    workspace_account_owner_name: Annotated[
        str,
        "The name of the account owner for the workspace you want to fetch application meta information from.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetch meta information of applications in a workspace.

    Use this tool to retrieve the meta information for applications hosted in a specific workspace you have access to. Useful for gaining insights into application details."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/applications".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=workspace_account_owner_name,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(
    requires_auth=OAuth2(id="arcade-zoho", scopes=["ZohoCreator.meta.application.READ"]),
    requires_secrets=["ZOHO_SERVER_URL"],
)
async def fetch_zoho_form_meta_information(
    context: ToolContext,
    zoho_account_owner_name: Annotated[
        str,
        "The name of the account owner for the Zoho Creator application. Required for authentication and identifying the account context.",  # noqa: E501
    ],
    zoho_app_link_name: Annotated[
        str,
        "The unique link name of the Zoho Creator application. This identifies the app whose form meta information is to be fetched.",  # noqa: E501
    ],
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Fetch meta information of Zoho Creator app forms.

    This tool retrieves the meta information of all forms in a specified Zoho Creator application. Use it to obtain details about the forms within the application."""  # noqa: E501
    request_data = remove_none_values({})
    response = await make_request(
        url="{zoho_server_url}/creator/v2/meta/{account_owner_name}/{app_link_name}/forms".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=zoho_app_link_name,
        ),
        method="GET",
        params=remove_none_values({}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data) if request_data else None,
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}


@tool(requires_auth=OAuth2(id="arcade-zoho"), requires_secrets=["ZOHO_SERVER_URL"])
async def add_records_to_zoho_form(
    context: ToolContext,
    mode: Annotated[
        ToolMode,
        "Operation mode: 'get_request_schema' returns the OpenAPI spec "
        "for the request body, 'execute' performs the actual operation",
    ],
    form_private_link: Annotated[
        str | None,
        "The unique identifier for accessing a specific form in Zoho Creator securely. Required for access control.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    zoho_account_owner_name: Annotated[
        str | None,
        "The account owner's name associated with the Zoho Creator application. This is needed to authenticate and route the records correctly.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    application_link_name: Annotated[
        str | None,
        "The unique identifier for the Zoho application where the form resides. Required to locate the specific application.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    zoho_form_link_name: Annotated[
        str | None,
        "The unique link name of the form in Zoho Creator where records will be added.  Required when mode is 'execute', ignored when mode is 'get_request_schema'.",  # noqa: E501
    ] = None,
    request_body: Annotated[
        str | None,
        "Stringified JSON representing the request body. Required when "
        "mode is 'execute', ignored when mode is 'get_request_schema'",
    ] = None,
) -> Annotated[dict[str, Any], "Response from the API endpoint ''."]:
    """Add multiple records to a Zoho Creator form efficiently.

    Use this tool to add up to 200 records at once to a specified form within your Zoho Creator application. Each JSON object in the input represents a record to be added, subject to validation. Suitable for situations needing bulk data import or batch entry creation.

    Note: Understanding the request schema is necessary to properly create
    the stringified JSON input object for execution.\n\nThis operation also requires path, query parameters.

    Modes:
    - GET_REQUEST_SCHEMA: Returns the schema. Only call if you don't
      already have it. Do NOT call repeatedly if you already received
      the schema.
    - EXECUTE: Performs the operation with the provided request body
      JSON.\n      Note: You must also provide the required path, query parameters when executing.

    If you need the schema, call with mode='get_request_schema' ONCE, then execute.
    """  # noqa: E501
    if mode == ToolMode.GET_REQUEST_SCHEMA:
        return {
            "request_body_schema": REQUEST_BODY_SCHEMAS["ADDRECORDSTOZOHOFORM_REQUEST_BODY_SCHEMA"],
            "instructions": (
                "Use the request_body_schema to construct a valid JSON object. "
                "Once you have populated the object following the schema "
                "structure and requirements, call this tool again with "
                "mode='execute' and the stringified JSON as the "
                "request_body parameter along with the required path, query parameters. "
                "Do NOT call the schema mode again - you already have "
                "the schema now."
            ),
        }

    # Mode is EXECUTE - validate parameters
    # Validate required query parameter: form_private_link
    if not form_private_link:
        raise RetryableToolError(
            message="Invalid or missing form_private_link parameter",
            developer_message=f"Query parameter "
            f"'form_private_link' validation failed. "
            f"Received: {form_private_link}",
            additional_prompt_content=(
                "The 'form_private_link' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "form_private_link value."
            ),
        )

    # Validate required path parameter: zoho_account_owner_name
    if not zoho_account_owner_name:
        raise RetryableToolError(
            message="Invalid or missing zoho_account_owner_name parameter",
            developer_message=f"Path parameter "
            f"'zoho_account_owner_name' validation failed. "
            f"Received: {zoho_account_owner_name}",
            additional_prompt_content=(
                "The 'zoho_account_owner_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "zoho_account_owner_name value."
            ),
        )

    # Validate required path parameter: application_link_name
    if not application_link_name:
        raise RetryableToolError(
            message="Invalid or missing application_link_name parameter",
            developer_message=f"Path parameter "
            f"'application_link_name' validation failed. "
            f"Received: {application_link_name}",
            additional_prompt_content=(
                "The 'application_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "application_link_name value."
            ),
        )

    # Validate required path parameter: zoho_form_link_name
    if not zoho_form_link_name:
        raise RetryableToolError(
            message="Invalid or missing zoho_form_link_name parameter",
            developer_message=f"Path parameter "
            f"'zoho_form_link_name' validation failed. "
            f"Received: {zoho_form_link_name}",
            additional_prompt_content=(
                "The 'zoho_form_link_name' parameter is required when "
                "executing this operation. "
                "Please call this tool again with a valid "
                "zoho_form_link_name value."
            ),
        )

    # Validate request body is provided (not None or empty string)
    # Note: Empty objects like {} are allowed - schema validation will check if valid
    if request_body is None or request_body.strip() == "":
        raise RetryableToolError(
            message="Request body is required when mode is 'execute'",
            developer_message="The request_body parameter was null or empty string",
            additional_prompt_content=(
                "The request body is required to perform this operation. "
                "Use the schema below to construct a valid JSON object, "
                "then call this tool again in execute mode with the "
                "stringified JSON as the request_body parameter.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["ADDRECORDSTOZOHOFORM_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        )

    # Parse JSON
    try:
        request_data = json.loads(request_body)
    except json.JSONDecodeError as e:
        raise RetryableToolError(
            message=f"Invalid JSON in request body: {e!s}",
            developer_message=f"JSON parsing failed: {e!s}",
            additional_prompt_content=(
                f"The request body contains invalid JSON. Error: {e!s}\n\n"
                "Please provide a valid JSON string that matches the schema "
                "below, then call this tool again in execute mode.\n\n"
                "Schema:\n\n"
                + json.dumps(
                    REQUEST_BODY_SCHEMAS["ADDRECORDSTOZOHOFORM_REQUEST_BODY_SCHEMA"], indent=2
                )
            ),
        ) from e

    # Validate against schema
    is_valid, validation_error = validate_json_against_schema(
        request_data, REQUEST_BODY_SCHEMAS["ADDRECORDSTOZOHOFORM_REQUEST_BODY_SCHEMA"]
    )
    if not is_valid:
        raise RetryableToolError(
            message=f"Request body validation failed: {validation_error}",
            developer_message=f"Schema validation error: {validation_error}",
            additional_prompt_content=(
                f"The request body does not match the required schema. "
                f"Errors:\n{validation_error}\n\n"
                "Please fix the validation errors above and call this tool "
                "again in execute mode with the corrected JSON.\n\n"
                "Required schema:\n\n"
                f"{json.dumps(REQUEST_BODY_SCHEMAS['ADDRECORDSTOZOHOFORM_REQUEST_BODY_SCHEMA'], indent=2)}"  # noqa: E501
            ),
        )

    # Make the actual API request
    response = await make_request(
        url="{zoho_server_url}/creator/v2/publish/{account_owner_name}/{app_link_name}/form/{form_link_name}".format(
            zoho_server_url=context.get_secret("ZOHO_SERVER_URL"),
            account_owner_name=zoho_account_owner_name,
            app_link_name=application_link_name,
            form_link_name=zoho_form_link_name,
        ),
        method="POST",
        params=remove_none_values({"privatelink": form_private_link}),
        headers=remove_none_values({
            "Authorization": "Bearer {authorization}".format(  # noqa: UP032
                authorization=context.get_auth_token_or_empty()
            )
        }),
        data=json.dumps(request_data),
    )
    try:
        return {"response_json": response.json()}
    except Exception:
        return {"response_text": response.text}
