# Copyright (c) 2026 동일비전(Dongil Vision Korea). All Rights Reserved.
"""확대/축소 이미지 뷰 — tab_camera.py에서 분리

ZoomView, CameraView.
"""

from typing import Optional

import cv2
import numpy as np
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QColor, QFontMetrics, QImage, QMouseEvent, QPainter, QPen, QPixmap, QWheelEvent
from PySide6.QtWidgets import QPushButton, QWidget

from ConfigReader import GlobalConfig
from utils.config_log import logger as log

# 줌 상수
MIN_ZOOM, MAX_ZOOM, ZOOM_DELTA = 0.1, 10.0, 0.1


class ZoomView(QWidget):
    """확대/축소 이미지 뷰"""
    WIDGET_STYLE = "ZoomView { background-color: #222; border: 2px solid #666; border-radius: 5px; color: #888; }"
    BUTTON_STYLE = """QPushButton { background-color: rgba(85,85,85,180); color: white; border: 2px solid rgba(102,102,102,200);
        border-radius: 5px; font-size: 12px; font-weight: bold; padding: 5px; }
        QPushButton:hover { background-color: rgba(102,102,102,220); }
        QPushButton:pressed { background-color: rgba(68,68,68,220); }"""

    CAMERA_BUTTON_STYLE_CONNECTED = """QPushButton { background-color: rgba(76,175,80,180); color: white; border: 2px solid rgba(102,102,102,200);
        border-radius: 5px; font-size: 14px; padding: 5px; }"""
    CAMERA_BUTTON_STYLE_DISCONNECTED = """QPushButton { background-color: rgba(244,67,54,180); color: white; border: 2px solid rgba(102,102,102,200);
        border-radius: 5px; font-size: 14px; padding: 5px; }"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumSize(640, 480)
        self.setStyleSheet(self.WIDGET_STYLE)
        self.setMouseTracking(True)

        # 카메라 상태 버튼
        self.camera_status_button = QPushButton("CAM", self)
        self.camera_status_button.setFixedSize(70, 30)
        self.camera_status_button.setFocusPolicy(Qt.NoFocus)
        self.camera_status_button.setStyleSheet(self.CAMERA_BUTTON_STYLE_DISCONNECTED)
        self.camera_status_button.setToolTip("카메라 연결 안됨")
        self.camera_status_button.raise_()

        self.full_button = QPushButton("Full", self)
        self.full_button.setFixedSize(60, 30)
        self.full_button.setCursor(Qt.PointingHandCursor)
        self.full_button.setFocusPolicy(Qt.NoFocus)
        self.full_button.setStyleSheet(self.BUTTON_STYLE)
        self.full_button.clicked.connect(self.fit_to_screen)
        self.full_button.raise_()

        self.original_pixmap: Optional[QPixmap] = None
        self.display_text = "카메라 연결 후 이미지가 표시됩니다"
        self.show_crosshair = True
        self.zoom_factor = 1.0
        self.pan_offset = QPointF(0, 0)
        self.is_panning = False
        self.last_mouse_pos = QPointF()
        self.is_camera_connected = False

    def set_crosshair_visible(self, visible: bool):
        if self.show_crosshair != visible:
            self.show_crosshair = visible
            self.update()

    def set_image(self, image: np.ndarray):
        if image is None or image.size == 0:
            self.original_pixmap = None
        else:
            try:
                img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) if len(image.shape) == 3 else image
                h, w = img_rgb.shape[:2]
                bpl = w * (3 if len(img_rgb.shape) == 3 else 1)
                fmt = QImage.Format_RGB888 if len(img_rgb.shape) == 3 else QImage.Format_Grayscale8
                self.original_pixmap = QPixmap.fromImage(QImage(img_rgb.data, w, h, bpl, fmt))
            except Exception as e:
                log.error(f"[ZoomView] 이미지 변환 실패: {e}")
        self.update()

    def reset_view(self):
        self.zoom_factor = 1.0
        self.pan_offset = QPointF(0, 0)
        self.update()

    def fit_to_screen(self):
        if self.original_pixmap and not self.original_pixmap.isNull():
            scale = min(self.width() / self.original_pixmap.width(), self.height() / self.original_pixmap.height())
            self.zoom_factor = max(MIN_ZOOM, min(scale, MAX_ZOOM))
            self.pan_offset = QPointF(0, 0)
            self.update()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.full_button.move(self.width() - 70, 10)
        self.camera_status_button.move(self.width() - 150, 10)

    def set_camera_status(self, is_connected: bool):
        """카메라 연결 상태 업데이트"""
        self.is_camera_connected = is_connected
        if is_connected:
            self.camera_status_button.setStyleSheet(self.CAMERA_BUTTON_STYLE_CONNECTED)
            self.camera_status_button.setToolTip("카메라 연결됨")
        else:
            self.camera_status_button.setStyleSheet(self.CAMERA_BUTTON_STYLE_DISCONNECTED)
            self.camera_status_button.setToolTip("카메라 연결 안됨")
        self.update()

    def wheelEvent(self, event: QWheelEvent):
        if not self.original_pixmap:
            return
        mouse_pos = event.position()
        scene_before = self._widget_to_scene(mouse_pos)
        zoom_delta = ZOOM_DELTA if event.angleDelta().y() > 0 else -ZOOM_DELTA
        self.zoom_factor = max(MIN_ZOOM, min(self.zoom_factor + zoom_delta, MAX_ZOOM))
        scene_after = self._widget_to_scene(mouse_pos)
        self.pan_offset -= (scene_after - scene_before)
        self.update()
        event.accept()

    def mousePressEvent(self, event: QMouseEvent):
        if self.full_button.geometry().contains(event.pos()):
            event.ignore()
            return
        if event.button() == Qt.LeftButton and self.original_pixmap:
            self.is_panning = True
            self.last_mouse_pos = event.position()
            self.setCursor(Qt.ClosedHandCursor)
            event.accept()

    def mouseMoveEvent(self, event: QMouseEvent):
        if self.full_button.geometry().contains(event.pos()):
            return
        if self.is_panning:
            self.pan_offset += event.position() - self.last_mouse_pos
            self.last_mouse_pos = event.position()
            self.update()
            event.accept()
        elif self.original_pixmap:
            self.setCursor(Qt.OpenHandCursor)

    def mouseReleaseEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            self.is_panning = False
            self.setCursor(Qt.OpenHandCursor if self.original_pixmap else Qt.ArrowCursor)
            event.accept()

    def draw_crosshair(self, painter: QPainter, imgBox: QRectF):
        if not self.original_pixmap or imgBox.isNull():
            return
        cfg = GlobalConfig.instance()
        pixels_per_mm = cfg.getConfigValue("core.pixels_per_mm", 110.0)
        circle_mark_size_mm = cfg.getConfigValue("core.circle_mark_size", 1.75)
        center_offset = cfg.getConfigValue("core.center_offset", [0, 0])

        circle_diameter = circle_mark_size_mm * pixels_per_mm * self.zoom_factor
        cx = imgBox.center().x() + center_offset[0]
        cy = imgBox.center().y() + center_offset[1]

        painter.setPen(QPen(QColor(255, 0, 0), 2))
        painter.drawEllipse(QPointF(cx, cy), circle_diameter / 2, circle_diameter / 2)

        painter.setPen(QPen(QColor(255, 0, 0), 1))
        cross_size = 30 * self.zoom_factor
        painter.drawLine(cx - cross_size, cy, cx + cross_size, cy)
        painter.drawLine(cx, cy - cross_size, cx, cy + cross_size)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.SmoothPixmapTransform)
        painter.fillRect(self.rect(), QColor(34, 34, 34))

        if not self.original_pixmap or self.original_pixmap.isNull():
            painter.setPen(QColor(136, 136, 136))
            painter.drawText(self.rect(), Qt.AlignCenter, self.display_text)
        else:
            center = QPointF(self.width() / 2, self.height() / 2)
            w = self.original_pixmap.width() * self.zoom_factor
            h = self.original_pixmap.height() * self.zoom_factor
            x = center.x() - w / 2 + self.pan_offset.x()
            y = center.y() - h / 2 + self.pan_offset.y()
            imgBox = QRectF(x, y, w, h)
            painter.drawPixmap(imgBox, self.original_pixmap, QRectF(self.original_pixmap.rect()))
            if self.show_crosshair:
                self.draw_crosshair(painter, imgBox)

        # 카메라 연결 안됨 배너
        if not self.is_camera_connected:
            banner_text = "카메라가 연결되지 않았습니다."
            font = painter.font()
            font.setPointSize(16)
            font.setBold(True)
            painter.setFont(font)

            # 배너 배경
            fm = QFontMetrics(font)
            text_width = fm.horizontalAdvance(banner_text)
            text_height = fm.height()
            padding_h, padding_v = 40, 20
            border_radius = 10
            banner_rect = QRectF(
                (self.width() - text_width) / 2 - padding_h,
                (self.height() - text_height) / 2 - padding_v,
                text_width + padding_h * 2,
                text_height + padding_v * 2
            )
            painter.setBrush(QColor(180, 50, 50, 200))
            painter.setPen(QPen(QColor(255, 255, 255), 2))
            painter.drawRoundedRect(banner_rect, border_radius, border_radius)

            # 배너 텍스트
            painter.setPen(QColor(255, 255, 255))
            painter.drawText(self.rect(), Qt.AlignCenter, banner_text)

        painter.end()

    def _widget_to_scene(self, pos: QPointF) -> QPointF:
        if not self.original_pixmap:
            return QPointF()
        center = QPointF(self.width() / 2, self.height() / 2)
        offset = pos - center
        return QPointF((offset.x() - self.pan_offset.x()) / self.zoom_factor,
                       (offset.y() - self.pan_offset.y()) / self.zoom_factor)


class CameraView(ZoomView):
    pass
