from __future__ import annotations

import re
from typing import Any

from backend.services.artifact_models import PreparedToolSourceArtifact
from backend.services.pptx_artifact_generation.models import PptxImageAsset


def build_image_assets_from_source_artifacts(
    source_artifacts: list[PreparedToolSourceArtifact],
) -> list[PptxImageAsset]:
    """Flatten selected source image artifacts into the ordered deck-local asset registry.

    The ordering rule is intentionally simple and stable for promptability: artifact order first, then image-part
    order inside each artifact. The resulting `img_1`, `img_2`, ... ids are what the LLM references in deck YAML.
    """
    assets: list[PptxImageAsset] = []
    for source_artifact in source_artifacts:
        sendable_index = 0
        for part in source_artifact.parts:
            if part.get("type") != "IMAGE_INLINE":
                continue
            inline_image = part.get("inlineImage")
            image_mime_type = part.get("imageMimeType")
            if not isinstance(inline_image, str) or not isinstance(image_mime_type, str):
                continue
            assets.append(
                PptxImageAsset(
                    asset_id=f"img_{len(assets) + 1}",
                    source_reference=source_artifact.reference,
                    image_part_index=sendable_index,
                    mime_type=image_mime_type,
                    data_base64=inline_image,
                    artifact_name=source_artifact.artifact_name,
                )
            )
            sendable_index += 1
    return assets


def build_image_assets_map(image_assets: list[PptxImageAsset]) -> dict[str, PptxImageAsset]:
    """Index resolved assets by deck-local id for rendering and validation."""

    return {asset.asset_id: asset for asset in image_assets}


def build_generation_image_assets_metadata(image_assets: list[PptxImageAsset]) -> dict[str, dict[str, Any]]:
    """Persist only the image bindings that must survive into future deck revisions."""

    return {asset.asset_id: asset.as_generation_metadata() for asset in image_assets}


def merge_image_assets(
    existing_assets: list[PptxImageAsset],
    additional_assets: list[PptxImageAsset],
) -> list[PptxImageAsset]:
    """Append new image assets after the current registry while keeping existing ids stable."""

    if not additional_assets:
        return list(existing_assets)

    next_asset_number = max((_parse_asset_number(asset.asset_id) for asset in existing_assets), default=0)
    merged_assets = list(existing_assets)
    for asset in additional_assets:
        next_asset_number += 1
        merged_assets.append(
            PptxImageAsset(
                asset_id=f"img_{next_asset_number}",
                source_reference=asset.source_reference,
                image_part_index=asset.image_part_index,
                mime_type=asset.mime_type,
                data_base64=asset.data_base64,
                artifact_name=asset.artifact_name,
            )
        )
    return merged_assets


def build_image_assets_prompt_section(image_assets: list[PptxImageAsset]) -> str:
    """Build the minimal LLM-facing registry of available source images for deck generation.

    This prompt section exposes only the stable `asset_id` values plus a short human label for each image. Backend
    storage references and persisted revision metadata stay out of the prompt and are handled separately.
    """
    if not image_assets:
        return ""

    lines = [
        "Available image assets for this deck:",
        "- Use only these exact asset ids when a slide should display one of the provided source images.",
        "- Use slide type `image` for a pure visual slide.",
        "- Use `image_text.asset_id` for a slide that combines one provided image with explanatory text.",
    ]
    for index, asset in enumerate(image_assets, start=1):
        label = asset.artifact_name or f"Image {index}"
        lines.append(f"- {asset.asset_id}: {label}")
    return "\n".join(lines)


def _parse_asset_number(asset_id: str) -> int:
    match = re.fullmatch(r"img_(\d+)", asset_id.strip())
    return int(match.group(1)) if match else 0
