"""
SuperTheme thumbnail generation using LibreOffice.

Generates proper thumbnail images for SuperTheme variants by:
1. Creating a minimal .pptx with the theme applied
2. Exporting to PNG via LibreOffice headless
3. Resizing to required thumbnail dimensions
"""

import subprocess
import tempfile
from pathlib import Path
from typing import Dict, Optional, Tuple

import structlog

try:
    from PIL import Image
except ImportError:
    Image = None

logger = structlog.get_logger(__name__)

# Required thumbnail sizes for SuperTheme
THUMBNAIL_SIZES = {
    "themeThumbnail.jpeg": (64, 48),
    "auxiliaryThemeThumbnail.jpeg": (85, 48),
    "auxiliaryThemeThumbnailMedium.jpeg": (124, 70),
    "thumbnail.jpeg": (341, 192),
}


def _find_soffice() -> Optional[str]:
    """Find the soffice executable path."""
    # macOS paths
    macos_paths = [
        "/Applications/LibreOffice.app/Contents/MacOS/soffice",
        "/Applications/OpenOffice.app/Contents/MacOS/soffice",
    ]
    # Linux/generic paths
    linux_paths = [
        "soffice",
        "libreoffice",
        "/usr/bin/soffice",
        "/usr/bin/libreoffice",
    ]

    for path in macos_paths + linux_paths:
        try:
            result = subprocess.run(
                [path, "--version"],
                capture_output=True,
                timeout=10,
            )
            if result.returncode == 0:
                return path
        except (FileNotFoundError, subprocess.TimeoutExpired):
            continue

    return None


def capture_theme_thumbnail_via_soffice(
    pptx_path: Path,
    output_path: Path,
    size: Tuple[int, int] = (341, 192),
) -> bool:
    """Capture a thumbnail from a PPTX using LibreOffice/soffice.

    Args:
        pptx_path: Path to the PPTX file
        output_path: Path for the output image (JPEG or PNG)
        size: Target size (width, height)

    Returns:
        True if successful, False otherwise
    """
    soffice = _find_soffice()
    if not soffice:
        logger.error("soffice/LibreOffice not found")
        return False

    if Image is None:
        logger.error("PIL/Pillow not available for image resizing")
        return False

    try:
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)

            # Export first slide to PNG using LibreOffice
            cmd = [
                soffice,
                "--headless",
                "--nologo",
                "--nolockcheck",
                "--convert-to",
                "png",
                "--outdir",
                str(temp_path),
                str(pptx_path),
            ]

            logger.debug("Running soffice", cmd=" ".join(cmd))

            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=60,
            )

            if result.returncode != 0:
                logger.error(
                    "soffice conversion failed",
                    returncode=result.returncode,
                    stderr=result.stderr,
                )
                return False

            # Find the generated PNG
            png_files = list(temp_path.glob("*.png"))
            if not png_files:
                logger.error("No PNG output from soffice")
                return False

            # Load and resize the image
            source_png = png_files[0]
            with Image.open(source_png) as img:
                # Convert to RGB if necessary (remove alpha)
                if img.mode in ("RGBA", "P"):
                    img = img.convert("RGB")

                # Resize maintaining aspect ratio then crop/pad to exact size
                img_resized = img.copy()
                img_resized.thumbnail(
                    (size[0] * 2, size[1] * 2), Image.Resampling.LANCZOS
                )

                # Resize to fill the thumbnail
                img_ratio = img.width / img.height
                target_ratio = size[0] / size[1]

                if img_ratio > target_ratio:
                    # Image is wider, fit to height
                    new_height = size[1]
                    new_width = int(size[1] * img_ratio)
                else:
                    # Image is taller, fit to width
                    new_width = size[0]
                    new_height = int(size[0] / img_ratio)

                img_scaled = img.resize(
                    (new_width, new_height), Image.Resampling.LANCZOS
                )

                # Crop to center
                left = (new_width - size[0]) // 2
                top = (new_height - size[1]) // 2
                img_cropped = img_scaled.crop(
                    (left, top, left + size[0], top + size[1])
                )

                # Save as JPEG
                output_path.parent.mkdir(parents=True, exist_ok=True)
                img_cropped.save(output_path, "JPEG", quality=85)

                logger.info("Thumbnail captured", output=str(output_path), size=size)
                return True

    except subprocess.TimeoutExpired:
        logger.error("soffice conversion timed out")
        return False
    except Exception as e:
        logger.error("Thumbnail capture failed", error=str(e))
        return False


def generate_thumbnails_from_pptx(
    pptx_path: Path,
) -> Dict[str, bytes]:
    """Generate all required SuperTheme thumbnails from a PPTX.

    Args:
        pptx_path: Path to a PPTX file with the theme applied

    Returns:
        Dict mapping filename to JPEG bytes
    """
    thumbnails = {}

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        for filename, size in THUMBNAIL_SIZES.items():
            output_file = temp_path / filename

            if capture_theme_thumbnail_via_soffice(pptx_path, output_file, size):
                thumbnails[filename] = output_file.read_bytes()
            else:
                logger.warning(
                    "Failed to generate thumbnail, using placeholder",
                    filename=filename,
                )
                # Fall back to placeholder
                from tokenmoulds.themes.supertheme import _create_placeholder_jpeg

                thumbnails[filename] = _create_placeholder_jpeg(
                    size[0], size[1], (128, 128, 128)
                )

    return thumbnails


def generate_thumbnails_from_theme(
    theme_path: Path,
    accent_color: str = "#4472C4",
) -> Dict[str, bytes]:
    """Generate thumbnails for a theme file (.thmx).

    Creates a temporary PPTX with the theme applied, then captures screenshots.

    Args:
        theme_path: Path to .thmx file
        accent_color: Primary accent color for fallback

    Returns:
        Dict mapping filename to JPEG bytes
    """
    try:
        # Create a minimal PPTX that uses the theme
        with tempfile.TemporaryDirectory() as temp_dir:
            temp_path = Path(temp_dir)
            pptx_path = temp_path / "sample.pptx"

            # Create a sample PPTX with theme colors
            # This requires building a minimal presentation
            if _create_sample_pptx_with_theme_colors(
                pptx_path, theme_path, accent_color
            ):
                return generate_thumbnails_from_pptx(pptx_path)

    except Exception as e:
        logger.error("Failed to generate thumbnails from theme", error=str(e))

    # Fall back to placeholder thumbnails
    from tokenmoulds.themes.supertheme import _create_placeholder_jpeg

    color = _hex_to_rgb(accent_color)
    return {
        filename: _create_placeholder_jpeg(size[0], size[1], color)
        for filename, size in THUMBNAIL_SIZES.items()
    }


def _create_sample_pptx_with_theme_colors(
    output_path: Path,
    theme_path: Path,
    accent_color: str,
) -> bool:
    """Create a sample PPTX demonstrating the theme.

    Creates a presentation with:
    - Title slide with theme colors
    - Sample shapes using accent colors
    - Text demonstrating fonts
    """
    try:
        # Use python-pptx if available for better control
        try:
            from pptx import Presentation  # type: ignore[import-not-found]
            from pptx.util import Inches, Pt  # type: ignore[import-not-found]
            from pptx.dml.color import RGBColor  # type: ignore[import-not-found]
            from pptx.enum.shapes import MSO_SHAPE  # type: ignore[import-not-found]

            prs = Presentation()

            # Set slide size (16:9)
            prs.slide_width = Inches(13.333)
            prs.slide_height = Inches(7.5)

            # Add a blank slide
            slide_layout = prs.slide_layouts[6]  # Blank layout
            slide = prs.slides.add_slide(slide_layout)

            # Add a large rectangle with accent color
            color_rgb = _hex_to_rgb(accent_color)
            left = Inches(0)
            top = Inches(0)
            width = prs.slide_width or Inches(10)
            height = Inches(2.5)

            shape = slide.shapes.add_shape(
                MSO_SHAPE.RECTANGLE, left, top, width, height
            )
            shape.fill.solid()
            shape.fill.fore_color.rgb = RGBColor(*color_rgb)
            shape.line.fill.background()

            # Add title text
            left = Inches(0.5)
            top = Inches(0.5)
            width = Inches(12)
            height = Inches(1.5)

            textbox = slide.shapes.add_textbox(left, top, width, height)
            tf = textbox.text_frame
            p = tf.paragraphs[0]
            p.text = "Theme Preview"
            p.font.size = Pt(44)
            p.font.bold = True
            p.font.color.rgb = RGBColor(255, 255, 255)

            # Add some sample content below
            content_top = Inches(3)
            content_width = Inches(4)
            content_height = Inches(3)

            # Sample accent boxes
            for i, x_offset in enumerate([1, 5, 9]):
                box = slide.shapes.add_shape(
                    MSO_SHAPE.ROUNDED_RECTANGLE,
                    Inches(x_offset),
                    content_top,
                    content_width,
                    content_height,
                )
                # Vary the color slightly
                if i == 0:
                    box.fill.solid()
                    box.fill.fore_color.rgb = RGBColor(*color_rgb)
                elif i == 1:
                    box.fill.solid()
                    # Lighter version
                    lighter = tuple(min(255, c + 60) for c in color_rgb)
                    box.fill.fore_color.rgb = RGBColor(*lighter)
                else:
                    box.fill.solid()
                    # Darker version
                    darker = tuple(max(0, c - 40) for c in color_rgb)
                    box.fill.fore_color.rgb = RGBColor(*darker)

                box.line.fill.background()

            prs.save(str(output_path))
            logger.info("Created sample PPTX", path=str(output_path))
            return True

        except ImportError:
            logger.warning("python-pptx not available, using minimal PPTX")
            # Fall back to minimal PPTX creation
            return _create_minimal_pptx(output_path, accent_color)

    except Exception as e:
        logger.error("Failed to create sample PPTX", error=str(e))
        return False


def _create_minimal_pptx(output_path: Path, accent_color: str) -> bool:
    """Create a minimal PPTX without python-pptx dependency."""
    try:
        # This would create a minimal valid PPTX
        # For now, return False to trigger placeholder fallback
        logger.warning("Minimal PPTX creation not implemented")
        return False
    except Exception as e:
        logger.error("Failed to create minimal PPTX", error=str(e))
        return False


def _hex_to_rgb(hex_color: str) -> Tuple[int, int, int]:
    """Convert hex color to RGB tuple."""
    hex_color = hex_color.lstrip("#")
    try:
        return (
            int(hex_color[0:2], 16),
            int(hex_color[2:4], 16),
            int(hex_color[4:6], 16),
        )
    except ValueError:
        return (128, 128, 128)


def is_soffice_available() -> bool:
    """Check if LibreOffice/soffice is available."""
    return _find_soffice() is not None


def get_soffice_version() -> Optional[str]:
    """Get the LibreOffice/soffice version string."""
    soffice = _find_soffice()
    if not soffice:
        return None

    try:
        result = subprocess.run(
            [soffice, "--version"],
            capture_output=True,
            text=True,
            timeout=10,
        )
        return result.stdout.strip() if result.returncode == 0 else None
    except Exception:
        return None


__all__ = [
    "capture_theme_thumbnail_via_soffice",
    "generate_thumbnails_from_pptx",
    "generate_thumbnails_from_theme",
    "is_soffice_available",
    "get_soffice_version",
    "THUMBNAIL_SIZES",
]
