"""Structured user-message attachments and model-context compatibility rendering."""
from __future__ import annotations

import mimetypes
from collections.abc import Iterable
from pathlib import Path
from typing import Any

from .artifacts import ArtifactPathError, resolve_artifact_path

ATTACHMENT_REF_VERSION = 1
MAX_ATTACHMENTS_PER_MESSAGE = 10
_IMAGE_EXTENSIONS = {
    ".avif", ".bmp", ".gif", ".heic", ".heif", ".jpeg", ".jpg",
    ".png", ".svg", ".tif", ".tiff", ".webp",
}


def _attachment_kind(requested: str, path: Path, media_type: str) -> str:
    detected_image = media_type.startswith("image/") or path.suffix.lower() in _IMAGE_EXTENSIONS
    if requested == "image" and detected_image:
        return "image"
    return "file"


def normalize_attachment_refs(
    refs: Iterable[Any], *, working_dir: Path, user_root: Path,
) -> list[dict]:
    """Validate client refs and return task-relative, display-ready metadata."""
    output: list[dict] = []
    seen: set[str] = set()
    for raw in refs:
        if len(output) >= MAX_ATTACHMENTS_PER_MESSAGE:
            raise ArtifactPathError(
                f"at most {MAX_ATTACHMENTS_PER_MESSAGE} attachments are allowed"
            )
        data = raw.model_dump() if hasattr(raw, "model_dump") else dict(raw or {})
        absolute, rel = resolve_artifact_path(
            str(data.get("path") or ""),
            working_dir=working_dir,
            user_root=user_root,
            require_file=True,
        )
        if rel in seen:
            continue
        seen.add(rel)
        media_type = mimetypes.guess_type(absolute.name)[0] or "application/octet-stream"
        label = str(data.get("label") or absolute.name).strip() or absolute.name
        output.append({
            "version": ATTACHMENT_REF_VERSION,
            "scope": "working_dir",
            "path": rel,
            "label": label,
            "kind": _attachment_kind(str(data.get("kind") or "file"), absolute, media_type),
            "media_type": media_type,
            "size_bytes": absolute.stat().st_size,
        })
    return output


def content_for_model(content: str, refs: Iterable[dict], working_dir_name: str) -> str:
    """Append the legacy-readable file hints only to the provider-bound message."""
    lines: list[str] = []
    wd = str(working_dir_name or "").strip().strip("/\\")
    for ref in refs or ():
        path = str((ref or {}).get("path") or "").strip().replace("\\", "/")
        if not path:
            continue
        full_path = f"{wd}/{path}" if wd else path
        marker = "[用户上传的参考图]" if (ref or {}).get("kind") == "image" else "[用户上传的文件]"
        lines.append(f"{marker} {full_path}")
    text = str(content or "").strip()
    if not lines:
        return text
    suffix = "\n".join(lines)
    return f"{text}\n\n{suffix}" if text else suffix
