"""
Asset drop mixin for GLWidget - handles drag-and-drop file operations
"""

from pyPhotoAlbum.models import ImageData, PlaceholderData
from pyPhotoAlbum.commands import AddElementCommand


class AssetDropMixin:
    """
    Mixin providing drag-and-drop asset functionality.

    This mixin handles dragging image files into the widget and creating
    or updating ImageData elements.
    """

    IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"]

    def dragEnterEvent(self, event):
        """Handle drag enter events"""
        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            for url in urls:
                file_path = url.toLocalFile()
                if any(file_path.lower().endswith(ext) for ext in self.IMAGE_EXTENSIONS):
                    event.acceptProposedAction()
                    return
        event.ignore()

    def dragMoveEvent(self, event):
        """Handle drag move events"""
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
        else:
            event.ignore()

    def dropEvent(self, event):
        """Handle drop events - delegates to specialized handlers"""
        image_path = self._extract_image_path(event)
        if not image_path:
            event.ignore()
            return

        x, y = event.position().x(), event.position().y()
        target_element = self._get_element_at(x, y)

        if target_element and isinstance(target_element, (ImageData, PlaceholderData)):
            self._handle_drop_on_element(image_path, target_element)
        else:
            self._handle_drop_on_empty_space(image_path, x, y)

        event.acceptProposedAction()
        self.update()

    def _extract_image_path(self, event):
        """Extract the first valid image path from drop event"""
        if not event.mimeData().hasUrls():
            return None

        for url in event.mimeData().urls():
            file_path = url.toLocalFile()
            if any(file_path.lower().endswith(ext) for ext in self.IMAGE_EXTENSIONS):
                return file_path
        return None

    def _handle_drop_on_element(self, image_path, target_element):
        """Handle dropping an image onto an existing element"""
        main_window = self.window()
        if not (hasattr(main_window, "project") and main_window.project):
            return

        try:
            asset_path = main_window.project.asset_manager.import_asset(image_path)

            if isinstance(target_element, PlaceholderData):
                self._replace_placeholder_with_image(target_element, asset_path, main_window)
            else:
                target_element.image_path = asset_path

            print(f"Updated element with image: {asset_path}")
        except Exception as e:
            print(f"Error importing dropped image: {e}")

    def _replace_placeholder_with_image(self, placeholder, asset_path, main_window):
        """Replace a placeholder element with an ImageData element"""
        new_image = ImageData(
            image_path=asset_path,
            x=placeholder.position[0],
            y=placeholder.position[1],
            width=placeholder.size[0],
            height=placeholder.size[1],
            z_index=placeholder.z_index,
            # Inherit styling from placeholder (for templatable styles)
            style=placeholder.style.copy(),
        )

        if not main_window.project.pages:
            return

        for page in main_window.project.pages:
            if placeholder in page.layout.elements:
                page.layout.elements.remove(placeholder)
                page.layout.add_element(new_image)
                break

    def _handle_drop_on_empty_space(self, image_path, x, y):
        """Handle dropping an image onto empty space"""
        main_window = self.window()
        if not (hasattr(main_window, "project") and main_window.project and main_window.project.pages):
            return

        target_page, page_index, page_renderer = self._get_page_at(x, y)

        if not (target_page and page_renderer):
            print("Drop location not on any page")
            return

        try:
            # Import asset first, then calculate dimensions from imported asset
            asset_path = main_window.project.asset_manager.import_asset(image_path)
            full_asset_path = self.get_asset_full_path(asset_path)
            img_width, img_height = self._calculate_image_dimensions(full_asset_path)

            self._add_new_image_to_page(
                asset_path, target_page, page_index, page_renderer, x, y, img_width, img_height, main_window
            )
        except Exception as e:
            print(f"Error importing dropped image: {e}")

    def _calculate_image_dimensions(self, image_path):
        """Calculate scaled image dimensions for new image using centralized utility."""
        from pyPhotoAlbum.async_backend import get_image_dimensions

        # Use centralized utility (max 300px for UI display)
        dimensions = get_image_dimensions(image_path, max_size=300)
        if dimensions:
            return dimensions

        # Fallback dimensions if image cannot be read
        return 200, 150

    def _add_new_image_to_page(
        self, asset_path, target_page, page_index, page_renderer, x, y, img_width, img_height, main_window
    ):
        """Add a new image element to the target page (asset already imported)"""
        if page_index >= 0:
            self.current_page_index = page_index

        page_local_x, page_local_y = page_renderer.screen_to_page(x, y)

        new_image = ImageData(image_path=asset_path, x=page_local_x, y=page_local_y, width=img_width, height=img_height)

        cmd = AddElementCommand(target_page.layout, new_image, asset_manager=main_window.project.asset_manager)
        main_window.project.history.execute(cmd)

        print(f"Added new image to page {page_index + 1} at ({page_local_x:.1f}, {page_local_y:.1f}): {asset_path}")
