"""Media player components for video, audio, image, and document preview."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/components/players.ipynb.

# %% auto #0
__all__ = ['TEXT_PREVIEWABLE_EXTENSIONS', 'is_text_previewable', 'read_text_content', 'render_video_player',
           'render_audio_player', 'render_image_viewer', 'render_text_viewer', 'render_document_preview',
           'render_media_player']

# %% ../../nbs/components/players.ipynb #c3d4e5f6
from typing import Any, Optional, Set, Tuple

from fasthtml.common import Div, Img, Video, Audio, Iframe, P, Source, Pre, Code

# Tailwind utilities
from cjm_fasthtml_tailwind.utilities.sizing import w, h, max_w, max_h, min_h
from cjm_fasthtml_tailwind.utilities.spacing import p, m
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import (
    flex_display, flex_direction, items, justify
)
from cjm_fasthtml_tailwind.utilities.backgrounds import bg
from cjm_fasthtml_tailwind.utilities.layout import object_fit, overflow
from cjm_fasthtml_tailwind.utilities.typography import font_family, whitespace, font_size
from cjm_fasthtml_tailwind.core.base import combine_classes

# DaisyUI utilities
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.utilities.border_radius import border_radius

# Local imports
from cjm_file_discovery.core.models import FileInfo, FileType

# %% ../../nbs/components/players.ipynb #e4trifoqoef
# Extensions that can be previewed as text content
TEXT_PREVIEWABLE_EXTENSIONS: Set[str] = {
    # Document text files
    'txt', 'md', 'rst',
    # Code files
    'py', 'js', 'ts', 'html', 'css', 'java', 'cpp', 'c', 'h', 'go', 'rs',
    'rb', 'php', 'swift', 'kt', 'scala', 'sh', 'bash', 'zsh',
    # Data text files
    'json', 'xml', 'csv', 'yaml', 'yml', 'sql', 'toml',
}

def is_text_previewable(
    file_info: FileInfo,  # File to check
) -> bool:  # True if file can be previewed as text
    """Check if a file can be previewed as text content."""
    if file_info.extension is None:
        return False
    return file_info.extension.lower() in TEXT_PREVIEWABLE_EXTENSIONS

# %% ../../nbs/components/players.ipynb #xm1v98l4gun
def read_text_content(
    file_path: str,  # Path to the file
    max_size: int = 10 * 1024 * 1024,  # Maximum file size in bytes (default 10MB)
) -> Tuple[Optional[str], Optional[str]]:  # (content, error_message)
    """Read text file content with encoding fallback."""
    import os
    
    # Check file size
    try:
        file_size = os.path.getsize(file_path)
        if file_size > max_size:
            return None, f"File too large ({file_size:,} bytes, max {max_size:,})"
    except OSError as e:
        return None, f"Cannot access file: {e}"
    
    # Try common encodings
    encodings = ['utf-8', 'latin-1', 'cp1252']
    
    for encoding in encodings:
        try:
            with open(file_path, 'r', encoding=encoding) as f:
                return f.read(), None
        except UnicodeDecodeError:
            continue
        except OSError as e:
            return None, f"Cannot read file: {e}"
    
    return None, "Unable to decode file with supported encodings"

# %% ../../nbs/components/players.ipynb #e5f6a7b8
def render_video_player(
    file_url: str,                    # URL to the video file
    file_info: Optional[FileInfo] = None,  # File metadata for MIME type
    autoplay: bool = False,           # Autoplay video on load
    loop: bool = False,               # Loop video playback
    muted: bool = False,              # Start muted
    poster: Optional[str] = None,     # Poster image URL
    cls: str = "",                    # Additional CSS classes
) -> Any:  # Video element
    """Render an HTML5 video player."""
    video_cls = combine_classes(
        max_w.full,
        max_h.full,
        border_radius.box,
        cls
    )
    
    # Build video attributes
    attrs = {
        "controls": True,
        "preload": "metadata",
        "cls": video_cls,
    }
    
    if autoplay:
        attrs["autoplay"] = True
    if loop:
        attrs["loop"] = True
    if muted:
        attrs["muted"] = True
    if poster:
        attrs["poster"] = poster
    
    # Determine MIME type
    mime_type = None
    if file_info and file_info.mime_type:
        mime_type = file_info.mime_type
    elif file_info and file_info.extension:
        mime_map = {
            "mp4": "video/mp4",
            "webm": "video/webm",
            "ogg": "video/ogg",
            "mov": "video/quicktime",
            "avi": "video/x-msvideo",
            "mkv": "video/x-matroska",
        }
        mime_type = mime_map.get(file_info.extension.lower())
    
    # Use Source element for better browser compatibility
    source_attrs = {"src": file_url}
    if mime_type:
        source_attrs["type"] = mime_type
    
    return Video(
        Source(**source_attrs),
        P("Your browser does not support the video element."),
        **attrs
    )

# %% ../../nbs/components/players.ipynb #h8c9d0e1
def render_audio_player(
    file_url: str,                    # URL to the audio file
    file_info: Optional[FileInfo] = None,  # File metadata for MIME type
    autoplay: bool = False,           # Autoplay audio on load
    loop: bool = False,               # Loop audio playback
    cls: str = "",                    # Additional CSS classes
) -> Any:  # Audio element container
    """Render an HTML5 audio player."""
    audio_cls = combine_classes(
        w.full,
        cls
    )
    
    # Build audio attributes
    attrs = {
        "controls": True,
        "preload": "metadata",
        "cls": audio_cls,
    }
    
    if autoplay:
        attrs["autoplay"] = True
    if loop:
        attrs["loop"] = True
    
    # Determine MIME type
    mime_type = None
    if file_info and file_info.mime_type:
        mime_type = file_info.mime_type
    elif file_info and file_info.extension:
        mime_map = {
            "mp3": "audio/mpeg",
            "wav": "audio/wav",
            "ogg": "audio/ogg",
            "flac": "audio/flac",
            "aac": "audio/aac",
            "m4a": "audio/mp4",
            "webm": "audio/webm",
        }
        mime_type = mime_map.get(file_info.extension.lower())
    
    # Use Source element for better browser compatibility
    source_attrs = {"src": file_url}
    if mime_type:
        source_attrs["type"] = mime_type
    
    return Audio(
        Source(**source_attrs),
        P("Your browser does not support the audio element."),
        **attrs
    )

# %% ../../nbs/components/players.ipynb #k1f2g3h4
def render_image_viewer(
    file_url: str,                    # URL to the image file
    file_info: Optional[FileInfo] = None,  # File metadata for alt text
    alt: Optional[str] = None,        # Alt text (uses filename if not provided)
    cls: str = "",                    # Additional CSS classes
) -> Any:  # Image element
    """Render an image viewer."""
    img_cls = combine_classes(
        max_w.full,
        max_h.full,
        object_fit.contain,
        border_radius.box,
        cls
    )
    
    # Determine alt text
    if alt is None:
        if file_info:
            alt = file_info.name
        else:
            alt = "Image"
    
    return Img(
        src=file_url,
        alt=alt,
        cls=img_cls,
        loading="lazy"
    )

# %% ../../nbs/components/players.ipynb #7oicwcw1akd
def render_text_viewer(
    content: str,  # Text content to display
    file_info: Optional[FileInfo] = None,  # File metadata for extension-based styling
    error: Optional[str] = None,  # Error message if content couldn't be read
    cls: str = "",  # Additional CSS classes
) -> Any:  # Text viewer component
    """Render a scrollable text viewer."""
    # If there's an error, show error message
    if error:
        container_cls = combine_classes(
            flex_display, items.center, justify.center,
            w.full, h(64),
            bg_dui.base_200, border_radius.box,
            text_dui.base_content,
            cls
        )
        return Div(
            Div(
                P("Unable to preview file", cls=str(font_size.lg)),
                P(error, cls=str(text_dui.base_content.opacity(60))),
                cls=combine_classes(flex_display, flex_direction.col, items.center)
            ),
            cls=container_cls
        )
    
    # Render text content in a scrollable pre/code block
    pre_cls = combine_classes(
        w.full,
        max_h.full,
        overflow.auto,
        p(4),
        bg_dui.base_200,
        border_radius.box,
        font_family.mono,
        font_size.sm,
        whitespace.pre,
        text_dui.base_content,
        cls
    )
    
    return Pre(
        Code(content),
        cls=pre_cls
    )

# %% ../../nbs/components/players.ipynb #n4i5j6k7
def render_document_preview(
    file_url: str,                    # URL to the document file
    file_info: Optional[FileInfo] = None,  # File metadata
    cls: str = "",                    # Additional CSS classes
) -> Any:  # Document preview element
    """Render a document preview."""
    # Get extension
    ext = ""
    if file_info and file_info.extension:
        ext = file_info.extension.lower()
    elif "." in file_url:
        ext = file_url.rsplit(".", 1)[-1].lower()
    
    # PDF can be embedded in iframe
    if ext == "pdf":
        iframe_cls = combine_classes(
            w.full,
            h.full,
            min_h(96),
            border_radius.box,
            cls
        )
        return Iframe(
            src=file_url,
            cls=iframe_cls,
            title=file_info.name if file_info else "Document"
        )
    
    # For other documents, show a placeholder with download link
    container_cls = combine_classes(
        flex_display, items.center, justify.center,
        w.full, h(64),
        bg_dui.base_200, border_radius.box,
        text_dui.base_content,
        cls
    )
    
    from cjm_fasthtml_media_gallery.core.icons import get_media_type_icon
    
    return Div(
        Div(
            get_media_type_icon(FileType.DOCUMENT, size=12),
            P(
                file_info.name if file_info else "Document",
                cls=str(m.t(4))
            ),
            P(
                f".{ext.upper()} file" if ext else "Document file",
                cls=str(text_dui.base_content.opacity(60))
            ),
            cls=combine_classes(flex_display, flex_direction.col, items.center)
        ),
        cls=container_cls
    )

# %% ../../nbs/components/players.ipynb #q7l8m9n0
def render_media_player(
    file_url: str,  # URL to the media file
    file_info: FileInfo,  # File metadata
    autoplay: bool = False,  # Autoplay audio/video
    text_content: Optional[str] = None,  # Pre-read text content for text files
    text_error: Optional[str] = None,  # Error message if text reading failed
    cls: str = "",  # Additional CSS classes
) -> Any:  # Media player component
    """Render the appropriate media player based on file type."""
    file_type = file_info.file_type
    
    # Check if this is a text-previewable file with content provided
    if is_text_previewable(file_info) and (text_content is not None or text_error is not None):
        return render_text_viewer(
            content=text_content or "",
            file_info=file_info,
            error=text_error,
            cls=cls
        )
    
    if file_type == FileType.VIDEO:
        return render_video_player(file_url, file_info, autoplay=autoplay, cls=cls)
    elif file_type == FileType.AUDIO:
        return render_audio_player(file_url, file_info, autoplay=autoplay, cls=cls)
    elif file_type == FileType.IMAGE:
        return render_image_viewer(file_url, file_info, cls=cls)
    elif file_type == FileType.DOCUMENT:
        return render_document_preview(file_url, file_info, cls=cls)
    else:
        # For other types, show document-style placeholder
        return render_document_preview(file_url, file_info, cls=cls)
