"""Functions for executing queries and mutations using Rekuest Next and Rath.

This function hook into the api funciton that are autogenerated by turms and
allow you to execute queries and mutations using thre rekuest-rath client.

"""

from typing import Any, Dict, Generator, AsyncGenerator
from pydantic import BaseModel
from fluss_next.rath import FlussRath, current_fluss_next_rath
from koil import unkoil
from koil.helpers import unkoil_gen
from rath.turms.funcs import TurmsOperation


def execute(
    operation: TurmsOperation, variables: Dict[str, Any], rath: FlussRath = None
) -> BaseModel:
    """Executes a query or mutation using rath in a blocking way."""
    return unkoil(aexecute, operation, variables, rath)


async def aexecute(
    operation: TurmsOperation, variables: Dict[str, Any], rath: FlussRath = None
) -> BaseModel:
    """Executes a query or mutation using rath in a non-blocking way."""
    rath = rath or current_fluss_next_rath.get()
    x = await rath.aquery(
        operation.Meta.document,
        operation.Arguments(**variables).model_dump(by_alias=True),
    )
    return operation(**x.data)


def subscribe(
    operation: TurmsOperation, variables: Dict[str, Any], rath: FlussRath = None
) -> Generator[BaseModel, None, None]:
    """Subscribes to a query or mutation using rath in a blocking way."""
    return unkoil_gen(asubscribe, operation, variables, rath)


async def asubscribe(
    operation: TurmsOperation, variables: Dict[str, Any], rath: FlussRath = None
) -> AsyncGenerator[BaseModel, None]:
    """Subscribes to a query or mutation using rath in a non-blocking way."""
    rath = rath or current_fluss_next_rath.get()
    async for event in rath.asubscribe(
        operation.Meta.document,
        operation.Arguments(**variables).model_dump(by_alias=True),
    ):
        yield operation(**event.data)
