from __future__ import annotations

from collections.abc import Callable

from django_anyllm.registry import ModelRegistry, default_registry

from .crud import (
    attach_file_to_instance,
    create_instance,
    delete_instance,
    get_instance,
    query_instances,
    update_instance,
)
from .introspection import describe_model, get_model_schema, list_registered_models

__all__ = [
    "get_tools",
    "get_introspection_tools",
    "get_crud_tools",
    "list_registered_models",
    "describe_model",
    "get_model_schema",
    "query_instances",
    "get_instance",
    "create_instance",
    "update_instance",
    "delete_instance",
    "attach_file_to_instance",
]


def get_tools(registry: ModelRegistry | None = None) -> list[Callable[..., object]]:
    """Return all LLM tools backed by *registry*.

    The returned callables can be passed directly to ``any_llm.completion(tools=...)``
    because ``any-llm-sdk`` converts plain Python callables to OpenAI tool format.

    Args:
        registry: The ``ModelRegistry`` to use. Defaults to the global registry.

    Returns:
        A list of introspection and CRUD tool functions.
    """
    return get_introspection_tools(registry) + get_crud_tools(registry)


def get_introspection_tools(
    registry: ModelRegistry | None = None,
) -> list[Callable[..., object]]:
    """Return only introspection tools backed by *registry*."""
    reg = registry or default_registry

    def _list_registered_models() -> list[dict]:
        return list_registered_models(reg)

    def _describe_model(app_label: str, model_name: str) -> dict:
        return describe_model(reg, app_label, model_name)

    def _get_model_schema(app_label: str, model_name: str) -> dict:
        return get_model_schema(reg, app_label, model_name)

    _list_registered_models.__doc__ = list_registered_models.__doc__
    _describe_model.__doc__ = describe_model.__doc__
    _get_model_schema.__doc__ = get_model_schema.__doc__

    return [_list_registered_models, _describe_model, _get_model_schema]


def get_crud_tools(
    registry: ModelRegistry | None = None,
) -> list[Callable[..., object]]:
    """Return only CRUD tools backed by *registry*."""
    reg = registry or default_registry

    def _query_instances(
        app_label: str,
        model_name: str,
        filters: dict[str, object] | None = None,
        limit: int = 20,
        offset: int = 0,
        ordering: list[str] | None = None,
    ) -> list[dict]:
        return query_instances(
            reg, app_label, model_name, filters, limit, offset, ordering
        )

    def _get_instance(app_label: str, model_name: str, pk: int) -> dict | None:
        return get_instance(reg, app_label, model_name, pk)

    def _create_instance(
        app_label: str, model_name: str, data: dict[str, object]
    ) -> dict:
        return create_instance(reg, app_label, model_name, data)

    def _update_instance(
        app_label: str, model_name: str, pk: int, data: dict[str, object]
    ) -> dict:
        return update_instance(reg, app_label, model_name, pk, data)

    def _delete_instance(app_label: str, model_name: str, pk: int) -> bool:
        return delete_instance(reg, app_label, model_name, pk)

    def _attach_file_to_instance(
        app_label: str,
        model_name: str,
        pk: int,
        field_name: str,
        message_file_id: int,
    ) -> dict:
        return attach_file_to_instance(
            reg, app_label, model_name, pk, field_name, message_file_id
        )

    _query_instances.__doc__ = query_instances.__doc__
    _get_instance.__doc__ = get_instance.__doc__
    _create_instance.__doc__ = create_instance.__doc__
    _update_instance.__doc__ = update_instance.__doc__
    _delete_instance.__doc__ = delete_instance.__doc__
    _attach_file_to_instance.__doc__ = attach_file_to_instance.__doc__

    return [
        _query_instances,
        _get_instance,
        _create_instance,
        _update_instance,
        _delete_instance,
        _attach_file_to_instance,
    ]
