# -*- coding: utf-8 -*-
# gui/components/model_view/_scenario_contour_edit.py
"""Сценарий редактирования контура зоны.

Охватывает:
- Drag узлов контура (ЛКМ hold + move)
- Candidate-узел контура (hover)
- Размерные линии (hover при _dim_enabled)
- Drag высоты выделения (mousePressEvent/Move/Release виджета)
"""

from __future__ import annotations

import math
from typing import TYPE_CHECKING

from PySide6.QtCore import Qt

from gui.components.model_view._interaction_scenario import (
    CameraPolicy,
    InteractionScenario,
)
from error_logger import log_exception

if TYPE_CHECKING:  # pragma: no cover
    from gui.components.model_view_widget import ModelViewWidget


class ContourEditScenario(InteractionScenario):
    """Сценарий редактирования контура: drag узлов, candidate hover, dim lines, height drag."""

    name = "contour_edit"
    camera_policy = CameraPolicy.TOP_VIEW

    # -- Активация / деактивация (backward compat) ----------------------------

    def on_activate(self, mv: "ModelViewWidget") -> None:
        mv._zone_selection_mode = True
        if hasattr(mv, "_set_trackball_right_button_enabled"):
            mv._set_trackball_right_button_enabled(False)

    def on_deactivate(self, mv: "ModelViewWidget") -> None:
        # Флаги сбрасываются в stop_contour_definition / cancel_zone_selection
        if hasattr(mv, "_set_trackball_right_button_enabled"):
            mv._set_trackball_right_button_enabled(True)

    # -- eventFilter: mouse press (ЛКМ — начать drag узла) --------------------

    def on_mouse_press(self, mv: "ModelViewWidget", event) -> bool:
        if event.button() == Qt.MouseButton.RightButton:
            if not mv.is_scenario_active("contour_edit"):
                return False
            world = mv._event_world_on_plane(event, mv._get_contour_plane_z())
            if world is not None:
                mv._handle_grid_click(float(world[0]), float(world[1]), float(world[2]), action="remove")
            else:
                if hasattr(mv, "set_contour_auxiliary_visibility"):
                    mv.set_contour_auxiliary_visibility(False)
            # ПКМ всегда поглощаем в contour_edit, чтобы камера не перехватывала событие.
            return True

        if event.button() != Qt.MouseButton.LeftButton:
            return False
        if not mv.is_scenario_active("contour_edit"):
            return False

        world = mv._event_world_on_plane(event, mv._get_contour_plane_z())
        if world is None:
            return False

        step = max(1.0, float(getattr(mv, "_current_zone_size", 1.0)))
        max_dist = step * 0.55

        nearest_idx = mv._nearest_contour_node_index(
            world[0], world[1], max_dist=max_dist,
        )
        if nearest_idx is None:
            return False
        if bool(getattr(mv, "_contour_aux_hidden", False)) and hasattr(mv, "set_contour_auxiliary_visibility"):
            mv.set_contour_auxiliary_visibility(True)

        mv._contour_drag_active = True
        mv._contour_drag_point_index = int(nearest_idx)
        mv._contour_drag_moved = False
        return True

    # -- eventFilter: mouse move (ЛКМ зажата — drag узла) --------------------

    def on_mouse_move(self, mv: "ModelViewWidget", event) -> bool:
        if not getattr(mv, "_contour_drag_active", False):
            return False
        if not (hasattr(event, "buttons") and (event.buttons() & Qt.MouseButton.LeftButton)):
            return False

        world = mv._event_world_on_plane(event, mv._get_contour_plane_z())
        if world is not None and mv._update_contour_drag_point(world[0], world[1]):
            mv._contour_drag_moved = True
            mv._safe_render(min_interval_s=1.0 / 75.0)
        return True

    # -- eventFilter: mouse release (ЛКМ — завершить drag) -------------------

    def on_mouse_release(self, mv: "ModelViewWidget", event) -> bool:
        if event.button() != Qt.MouseButton.LeftButton:
            return False
        if not getattr(mv, "_contour_drag_active", False):
            return False

        moved = bool(getattr(mv, "_contour_drag_moved", False))
        mv._contour_drag_active = False
        mv._contour_drag_point_index = None
        mv._contour_drag_moved = False
        if moved:
            mv.set_ignore_next_click(True)
        return True

    # -- eventFilter: hover (candidate узел + dim lines) ----------------------

    def on_hover(self, mv: "ModelViewWidget", event) -> None:
        if not mv.is_scenario_active("contour_edit"):
            return
        try:
            sx, sy = mv._event_to_vtk_display_xy(event)
            plane_z = mv._get_contour_plane_z()
            world = mv.screen_to_world_on_plane(sx, sy, plane_z)
            if world is not None:
                mv.update_contour_candidate_node(world[0], world[1])
                if getattr(mv, "_dim_enabled", False):
                    mv.handle_dim_hover(world[0], world[1])
        except Exception as _exc:
            log_exception(__name__, "on_hover", _exc)
    # -- eventFilter: горячие клавиши -----------------------------------------

    def on_key_press(self, mv: "ModelViewWidget", event) -> bool:
        if event.key() == Qt.Key.Key_Escape:
            # Первое ESC в контурном сценарии скрывает вспомогательные
            # визуалы (candidate/dim), не прерывая визард.
            if hasattr(mv, "set_contour_auxiliary_visibility") and not bool(getattr(mv, "_contour_aux_hidden", False)):
                mv.set_contour_auxiliary_visibility(False)
                return True
            cancel = getattr(mv, "_global_cancel_handler", None)
            if callable(cancel):
                try:
                    cancel()
                except Exception as _exc:
                    log_exception(__name__, "on_key_press", _exc)
                return True
        return False

    # -- mousePressEvent/Move/Release: drag высоты зоны -----------------------

    def on_widget_mouse_press(self, mv: "ModelViewWidget", event) -> bool:
        if (
            mv._zone_selection_mode
            and mv._selected_cells
            and event.button() == Qt.MouseButton.LeftButton
        ):
            mv._dragging = True
            mv._drag_start_y = event.y()
            event.accept()
            return True
        return False

    def on_widget_mouse_move(self, mv: "ModelViewWidget", event) -> bool:
        if mv._dragging and mv._zone_selection_mode:
            delta_y = mv._drag_start_y - event.y()
            if delta_y != 0:
                mv.update_height_from_mouse(delta_y)
                mv._drag_start_y = event.y()
            event.accept()
            return True
        return False

    def on_widget_mouse_release(self, mv: "ModelViewWidget", event) -> bool:
        if mv._dragging and event.button() == Qt.MouseButton.LeftButton:
            mv._dragging = False
            event.accept()
            return True
        return False
