"""
Виджет для отображения и манипуляции солнечными изображениями
Поддерживает: зум, панорамирование, композитинг слоев
"""

from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PySide6.QtCore import Qt, QRectF, QPointF, Signal
from PySide6.QtGui import QPixmap, QImage, QWheelEvent, QMouseEvent, QPainter
import numpy as np


class SolarCanvas(QGraphicsView):
    """
    Кастомный Canvas для отображения солнечных изображений
    Поддерживает масштабирование, панорамирование и наложение слоев
    """

    zoom_changed = Signal(float)

    def __init__(self, controller):
        super().__init__()
        self.controller = controller
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)

        # Настройки отображения - ИСПРАВЛЕНО: используем QPainter
        self.setRenderHint(QPainter.RenderHint.Antialiasing)
        self.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
        self.setDragMode(self.DragMode.ScrollHandDrag)
        self.setTransformationAnchor(self.ViewportAnchor.AnchorUnderMouse)
        self.setResizeAnchor(self.ViewportAnchor.AnchorUnderMouse)

        # Переменные для зума
        self.current_zoom = 1.0
        self.min_zoom = 0.1
        self.max_zoom = 10.0
        self.zoom_factor = 1.1

        # Словарь для хранения слоев (QGraphicsPixmapItem)
        self.layer_items = {}

        # Фон для лучшего контраста (черный для астрономических изображений)
        self.setBackgroundBrush(Qt.GlobalColor.black)

        # Дополнительные настройки для плавности
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)

    def set_image(self, layer_id: int, image_data: np.ndarray):
        """
        Устанавливает изображение для слоя

        Args:
            layer_id: ID слоя
            image_data: numpy массив с изображением
        """
        # Конвертируем numpy array в QImage
        height, width = image_data.shape[:2]

        if len(image_data.shape) == 2:
            # Черно-белое изображение
            bytes_per_line = width
            qimage = QImage(image_data.data, width, height, bytes_per_line, QImage.Format.Format_Grayscale8)
        else:
            # RGB изображение
            bytes_per_line = 3 * width
            qimage = QImage(image_data.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)

        # Конвертируем в QPixmap
        pixmap = QPixmap.fromImage(qimage)

        # Создаем или обновляем графический элемент
        if layer_id in self.layer_items:
            self.layer_items[layer_id].setPixmap(pixmap)
        else:
            item = self.scene.addPixmap(pixmap)
            self.layer_items[layer_id] = item

        # Центрируем изображение при первом добавлении
        if len(self.layer_items) == 1:
            self.centerOn(item)
            self.fitInView(item, Qt.AspectRatioMode.KeepAspectRatio)

    def set_layer_visibility(self, layer_id: int, visible: bool):
        """Устанавливает видимость слоя"""
        if layer_id in self.layer_items:
            self.layer_items[layer_id].setVisible(visible)

    def set_layer_opacity(self, layer_id: int, opacity: float):
        """Устанавливает прозрачность слоя"""
        if layer_id in self.layer_items:
            self.layer_items[layer_id].setOpacity(opacity)

    def remove_layer(self, layer_id: int):
        """Удаляет слой"""
        if layer_id in self.layer_items:
            self.scene.removeItem(self.layer_items[layer_id])
            del self.layer_items[layer_id]

    def clear_all_layers(self):
        """Очищает все слои"""
        for item in self.layer_items.values():
            self.scene.removeItem(item)
        self.layer_items.clear()

    def wheelEvent(self, event: QWheelEvent):
        """Обработка колесика мыши для зума"""
        # Определяем направление зума
        zoom_in = event.angleDelta().y() > 0

        # Вычисляем новый уровень зума
        if zoom_in:
            new_zoom = self.current_zoom * self.zoom_factor
        else:
            new_zoom = self.current_zoom / self.zoom_factor

        # Ограничиваем зум
        if self.min_zoom <= new_zoom <= self.max_zoom:
            self.current_zoom = new_zoom
            self.scale(self.zoom_factor if zoom_in else 1/self.zoom_factor,
                      self.zoom_factor if zoom_in else 1/self.zoom_factor)
            self.zoom_changed.emit(self.current_zoom)

    def mousePressEvent(self, event: QMouseEvent):
        """Обработка нажатия мыши для панорамирования"""
        if event.button() == Qt.MouseButton.MiddleButton:
            self.setDragMode(self.DragMode.ScrollHandDrag)
            # Создаем фейковое событие с левой кнопкой
            fake_event = QMouseEvent(
                event.type(), event.pos(), Qt.MouseButton.LeftButton,
                Qt.MouseButton.LeftButton, event.modifiers()
            )
            super().mousePressEvent(fake_event)
        else:
            super().mousePressEvent(event)

    def mouseReleaseEvent(self, event: QMouseEvent):
        """Обработка отпускания мыши"""
        if event.button() == Qt.MouseButton.MiddleButton:
            self.setDragMode(self.DragMode.NoDrag)
        super().mouseReleaseEvent(event)

    def reset_view(self):
        """Сбрасывает зум и позицию"""
        if self.layer_items:
            first_item = next(iter(self.layer_items.values()))
            self.fitInView(first_item, Qt.AspectRatioMode.KeepAspectRatio)
            self.current_zoom = 1.0
            self.zoom_changed.emit(self.current_zoom)