from __future__ import annotations

from dataclasses import dataclass
import hashlib
from pathlib import Path
from typing import Protocol

from core.agent.storage_adapter import StorageAdapter

_ALLOWED_MIME_TYPES = {
    "audio/mpeg",
    "audio/wav",
    "audio/x-wav",
    "image/jpeg",
    "image/png",
    "image/webp",
    "application/pdf",
    "text/plain",
}


class _AsrTool(Protocol):
    def transcribe(self, *, audio_bytes: bytes, filename: str) -> dict[str, object]: ...


@dataclass(frozen=True)
class AttachmentInput:
    filename: str
    mime_type: str
    content: bytes
    origin: str = "user_upload"


@dataclass(frozen=True)
class ProcessedAttachmentContext:
    attachments: list[dict[str, object]]
    preview_texts: list[str]


class MultimodalProcessor:
    def __init__(
        self,
        *,
        storage: StorageAdapter,
        asr_tool: _AsrTool,
        max_file_size_mb: int = 20,
    ) -> None:
        self._storage = storage
        self._asr_tool = asr_tool
        self._max_size_bytes = max_file_size_mb * 1024 * 1024

    def process(
        self,
        *,
        user_id: str,
        session_id: str,
        message_seq: int,
        attachments: list[AttachmentInput],
    ) -> ProcessedAttachmentContext:
        metadata_list: list[dict[str, object]] = []
        preview_texts: list[str] = []

        for attachment in attachments:
            self._validate_attachment(attachment)
            checksum = hashlib.sha256(attachment.content).hexdigest()
            extension = Path(attachment.filename).suffix.strip(".").lower() or "bin"
            object_path = self._storage.build_object_path(
                user_id=user_id,
                session_id=session_id,
                message_seq=message_seq,
                checksum_sha256=checksum,
                extension=extension,
            )

            preview_text = self._build_preview_text(attachment)
            if preview_text:
                preview_texts.append(preview_text)

            metadata = self._storage.build_attachment_metadata(
                object_path=object_path,
                mime_type=attachment.mime_type,
                size=len(attachment.content),
                checksum_sha256=checksum,
                origin=attachment.origin,
                preview_text=preview_text,
            )
            metadata_list.append(metadata)

        return ProcessedAttachmentContext(
            attachments=metadata_list,
            preview_texts=preview_texts,
        )

    def _validate_attachment(self, attachment: AttachmentInput) -> None:
        if attachment.mime_type not in _ALLOWED_MIME_TYPES:
            raise ValueError("Unsupported MIME type")
        if len(attachment.content) > self._max_size_bytes:
            raise ValueError("Attachment exceeds max file size")

    def _build_preview_text(self, attachment: AttachmentInput) -> str | None:
        if attachment.mime_type.startswith("audio/"):
            result = self._asr_tool.transcribe(
                audio_bytes=attachment.content,
                filename=attachment.filename,
            )
            text = result.get("text")
            if isinstance(text, str):
                return text
            return None
        if attachment.mime_type == "text/plain":
            return attachment.content.decode("utf-8", errors="ignore")[:200]
        return None
