from __future__ import annotations

from collections.abc import Callable
from types import SimpleNamespace
from typing import Any

import dataiku
from backend.agents.tools.generated_document_fields import (
    CONVERSATION_CONTEXT_DESCRIPTION,
    GENERATE_PPTX_FILENAME_DESCRIPTION,
    SOURCE_ARTIFACTS_DESCRIPTION,
)
from backend.agents.tools_using_v2 import LLMTool
from backend.config import get_default_llm_id
from backend.constants import GENERATE_PPTX_TOOL_NAME, GENERATE_PPTX_TOOL_REF
from backend.services.artifact_models import ArtifactReference, ArtifactReferenceSpec, PreparedToolSourceArtifact
from backend.services.pptx_artifact_generation.image_assets import (
    build_image_assets_from_source_artifacts,
)
from backend.services.pptx_artifact_generation.models import PptxImageAsset
from backend.services.pptx_artifact_generation.service import generate_pptx_artifacts
from backend.services.pptx_artifact_generation.source_artifacts import build_pptx_tool_user_message
from backend.services.tool_source_artifacts.source_artifact_input_service import prepare_source_artifacts_for_tool
from backend.utils.llm_utils import build_conversation_context_section
from pydantic import BaseModel, Field

PPTX_PROGRESS_EVENT_DATA = {"toolName": "Generate PPTX"}


class GeneratePptxSpec(BaseModel):
    query: str = Field(
        ...,
        description=(
            "Concise, complete, self-contained natural-language request describing the PPTX to generate, including "
            "topic, audience, tone, slide count, and any structure or content constraints."
        ),
    )
    filename: str | None = Field(
        default=None,
        description=GENERATE_PPTX_FILENAME_DESCRIPTION,
    )
    conversation_context: str | None = Field(
        default=None,
        description=CONVERSATION_CONTEXT_DESCRIPTION,
    )
    source_artifacts: list[ArtifactReferenceSpec] | None = Field(
        default=None,
        description=SOURCE_ARTIFACTS_DESCRIPTION,
    )


class GeneratePptxArtifactTool:
    def __init__(
        self,
        *,
        app=None,
        llm_id: str | None = None,
        progress_event_callback: Callable[[dict[str, Any]], None] | None = None,
        conversation_history: list[dict] | None = None,
    ):
        self._app = app
        self._llm_id = llm_id
        self._progress_event_callback = progress_event_callback
        self._conversation_history = conversation_history or []

    project_key = "AgentHub"
    tool_id = GENERATE_PPTX_TOOL_NAME
    tool_name = GENERATE_PPTX_TOOL_NAME

    def get_settings(self):
        return SimpleNamespace(_settings={"type": "builtin"})

    def describe_tool_call(self, input, llm_descriptor, context=None, subtool_name=None):
        query = ((input or {}).get("query") or "PPTX request").strip()
        if len(query) > 80:
            query = f"{query[:77]}..."
        return f"Generate a PPTX for '{query}'."

    def run(
        self,
        input,
        context=None,
        subtool_name=None,
        memory_fragment=None,
        tool_validation_responses=None,
        tool_validation_requests=None,
    ):
        spec = GeneratePptxSpec.model_validate(input or {})
        project = dataiku.api_client().get_default_project()
        llm_id = self._llm_id or get_default_llm_id()
        source_artifact_references = [
            ArtifactReference(
                message_id=source_artifact.message_id,
                artifacts_id=source_artifact.artifacts_id,
                artifact_index=source_artifact.artifact_index,
            )
            for source_artifact in (spec.source_artifacts or [])
        ]
        prepared_source_artifacts: list[PreparedToolSourceArtifact] = prepare_source_artifacts_for_tool(
            source_artifacts=source_artifact_references,
            context=context,
            app=self._app,
            accepted_read_modes={"records_preview", "inline_image"},
        )
        image_assets: list[PptxImageAsset] = build_image_assets_from_source_artifacts(prepared_source_artifacts)
        user_message = build_pptx_tool_user_message(
            query=spec.query,
            conversation_context_section=build_conversation_context_section(
                conversation_context=spec.conversation_context,
            ),
            source_artifacts=prepared_source_artifacts,
            image_assets=image_assets,
        )
        emit_progress_event = _build_progress_emitter(progress_event_callback=self._progress_event_callback)
        generated = generate_pptx_artifacts(
            project=project,
            llm_id=llm_id,
            user_prompt=spec.query,
            user_message=user_message,
            image_assets=image_assets,
            requested_filename=spec.filename,
            emit_progress_event=emit_progress_event,
            conversation_history=self._conversation_history,
        )

        return {
            "output": {
                "result": f"Generated PPTX: {generated.filename}",
            },
            "sources": [],
            "artifacts": generated.artifacts,
            "trace": None,
            "toolValidationRequests": None,
            "memoryFragment": None,
        }


def _build_progress_emitter(
    *,
    progress_event_callback: Callable[[dict[str, Any]], None] | None,
):
    if progress_event_callback is not None:

        def emit_progress(event_kind) -> None:
            progress_event_callback(
                {
                    "eventKind": event_kind,
                    "eventData": PPTX_PROGRESS_EVENT_DATA,
                }
            )

        return emit_progress

    return None


def build_generate_pptx_llm_tool(
    app=None,
    pcb: Callable[[dict[str, Any]], None] | None = None,
    llm_id: str | None = None,
    conversation_history: list[dict] | None = None,
) -> LLMTool:
    return LLMTool(
        llm_tool_name=GENERATE_PPTX_TOOL_NAME,
        llm_descriptor={
            "type": "function",
            "function": {
                "name": GENERATE_PPTX_TOOL_NAME,
                "description": (
                    "Generate an editable Microsoft PowerPoint PPTX artifact from a complete natural-language deck "
                    "brief. Use it for decks, slides, presentations, pitches, and audience walkthroughs. It creates "
                    "PPTX only, not PDF or other file formats."
                ),
                "parameters": GeneratePptxSpec.model_json_schema(),
            },
        },
        dku_tool=GeneratePptxArtifactTool(
            app=app,
            llm_id=llm_id,
            progress_event_callback=pcb,
            conversation_history=conversation_history,
        ),
        dku_tool_ref=GENERATE_PPTX_TOOL_REF,
        dku_tool_type="builtin",
        dku_tool_name="Generate PPTX",
        dku_subtool_name=None,
        require_validation=False,
        allow_editing_inputs=False,
    )
