"""
Son of Anton — File Processor
Handles classification, validation, and Claude content-block generation
for uploaded files (images, videos, documents).
"""

import base64
import mimetypes
from pathlib import Path

# Claude Bedrock supported formats
IMAGE_FORMATS = {"image/jpeg", "image/png", "image/gif", "image/webp"}
VIDEO_FORMATS = {"video/mp4", "video/webm", "video/mov", "video/mpeg", "video/mkv",
                 "video/x-matroska", "video/quicktime", "video/x-flv",
                 "video/x-ms-wmv", "video/3gpp"}
DOCUMENT_FORMATS = {
    "application/pdf": "pdf",
    "text/csv": "csv",
    "application/msword": "doc",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
    "application/vnd.ms-excel": "xls",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
    "text/html": "html",
    "text/plain": "txt",
    "text/markdown": "md",
}

# Max sizes (bytes)
MAX_IMAGE_SIZE = 20 * 1024 * 1024      # 20MB
MAX_VIDEO_SIZE = 100 * 1024 * 1024      # 100MB (Claude limit ~25MB for video in message)
MAX_DOCUMENT_SIZE = 50 * 1024 * 1024    # 50MB

ALLOWED_MIMES = IMAGE_FORMATS | VIDEO_FORMATS | set(DOCUMENT_FORMATS.keys())


def classify_media(mime_type: str) -> str:
    """Classify a MIME type into a media category."""
    if mime_type in IMAGE_FORMATS:
        return "image"
    if mime_type in VIDEO_FORMATS:
        return "video"
    if mime_type in DOCUMENT_FORMATS:
        return "document"
    if mime_type and mime_type.startswith("text/"):
        return "text"
    return "unknown"


def get_max_size(media_type: str) -> int:
    """Return max allowed file size in bytes for a media type."""
    return {
        "image": MAX_IMAGE_SIZE,
        "video": MAX_VIDEO_SIZE,
        "document": MAX_DOCUMENT_SIZE,
        "text": MAX_DOCUMENT_SIZE,
    }.get(media_type, MAX_DOCUMENT_SIZE)


def validate_file(filename: str, content_type: str, size: int) -> tuple[bool, str]:
    """Validate an uploaded file. Returns (ok, error_message)."""
    if not content_type:
        guessed, _ = mimetypes.guess_type(filename)
        content_type = guessed or "application/octet-stream"

    media_type = classify_media(content_type)

    if media_type == "unknown":
        return False, f"Unsupported file type: {content_type}. Supported: images, videos, PDF, Office docs, text files."

    max_size = get_max_size(media_type)
    if size > max_size:
        return False, f"File too large ({size / 1024 / 1024:.1f}MB). Max for {media_type}: {max_size / 1024 / 1024:.0f}MB."

    return True, ""


def mime_to_claude_format(mime_type: str, media_type: str) -> str:
    """Convert MIME type to Claude's format string."""
    if media_type == "image":
        return mime_type.split("/")[1]  # jpeg, png, gif, webp
    if media_type == "video":
        mapping = {
            "video/mp4": "mp4",
            "video/webm": "webm",
            "video/quicktime": "mov",
            "video/mov": "mov",
            "video/mpeg": "mpeg",
            "video/mkv": "mkv",
            "video/x-matroska": "mkv",
            "video/x-flv": "flv",
            "video/x-ms-wmv": "wmv",
            "video/3gpp": "three_gp",
        }
        return mapping.get(mime_type, "mp4")
    if media_type == "document":
        return DOCUMENT_FORMATS.get(mime_type, "txt")
    return "txt"


def build_content_block(file_path: str, mime_type: str, media_type: str, original_filename: str) -> dict:
    """
    Build a Claude Converse API content block for a file.
    Returns a dict that goes directly into the message content array.
    """
    path = Path(file_path)
    if not path.exists():
        return {"text": f"[Attachment missing: {original_filename}]"}

    file_bytes = path.read_bytes()
    fmt = mime_to_claude_format(mime_type, media_type)

    if media_type == "image":
        return {
            "image": {
                "format": fmt,
                "source": {
                    "bytes": file_bytes
                }
            }
        }
    elif media_type == "video":
        return {
            "video": {
                "format": fmt,
                "source": {
                    "bytes": file_bytes
                }
            }
        }
    elif media_type == "document":
        return {
            "document": {
                "format": fmt,
                "name": Path(original_filename).stem[:200],
                "source": {
                    "bytes": file_bytes
                }
            }
        }
    elif media_type == "text":
        try:
            text_content = file_bytes.decode("utf-8", errors="replace")
        except Exception:
            text_content = "[Could not decode text file]"
        return {
            "text": f"--- Content of {original_filename} ---\n{text_content}\n--- End of {original_filename} ---"
        }
    else:
        return {"text": f"[Unsupported attachment: {original_filename}]"}


def build_content_blocks_for_attachments(attachments: list, upload_dir: str) -> list[dict]:
    """
    Given a list of attachment DB records, build all Claude content blocks.
    """
    blocks = []
    for att in attachments:
        file_path = str(Path(upload_dir) / att["storage_path"])
        block = build_content_block(
            file_path=file_path,
            mime_type=att["mime_type"],
            media_type=att["media_type"],
            original_filename=att["original_filename"],
        )
        blocks.append(block)
    return blocks