"""
Дуга по 3 точкам.
"""

from typing import List, Tuple, cast

import axipy
from PySide2.QtCore import QPoint, QPointF, QRectF, QSizeF, Qt
from PySide2.QtGui import QPainter, QPen

from ..circle_utils import (
    CircleMapTool,
    center_and_radius_of_circle,
    ensure_util_geom_visual,
    insert_feature,
    start_end_angles,
)


class ArcByPoints(CircleMapTool):

    def __init__(self, iface: axipy.Plugin, title: str) -> None:
        super().__init__(iface, title)

    def prepare_to_draw(self, painter: QPainter, points: List[QPoint]):
        prepare_to_draw_qt_arc(painter, points)

    def prepare_to_insert(self) -> None:
        try:
            points = self.points
            points = ensure_util_geom_visual(self.view, points)
            points = cast(Tuple[axipy.Pnt, axipy.Pnt, axipy.Pnt], points)
            result = center_and_radius_of_circle(points)
            if result is None:
                raise Exception("None")

            center, radius = result
            if radius == 0:
                self.insert_line()
                self.clear_and_redraw()
                return None

            points = cast(List[axipy.Pnt], points)
            start_angle, end_angle = start_end_angles(points, center)
            self.insert_arc(center, radius, start_angle, end_angle)
        except Exception:
            axipy.Notifications.push(
                self.title,
                self.plugin.tr("Не удалось построить дугу по 3-м точкам. Попробуйте ещё раз, изменив координаты."),
                axipy.Notifications.Critical,
            )
        finally:
            self.clear_and_redraw()

    def insert_arc(self, c, r, a1, a2) -> None:
        rect = axipy.Rect(c.x - r, c.y - r, c.x + r, c.y + r)
        rect = ensure_util_geom_visual(self.view, rect, inverse=True)

        arc = axipy.Arc(rect, startAngle=a1, endAngle=a2, cs=self.view.coordsystem)
        style = axipy.Style.from_mapinfo("Pen (1, 2, 0)")
        f_arc = axipy.Feature(geometry=arc, style=style)
        feature = f_arc

        span_angle = a2 - a1
        span_angle = round(span_angle)
        if span_angle < 0:
            span_angle += 360
        if span_angle == 0:
            self.insert_line()
            return None

        insert_feature(feature)

        axipy.Notifications.push(self.title, self.plugin.tr("Дуга успешно добавлена."), axipy.Notifications.Success)

    def insert_line(self) -> None:
        line_str = axipy.LineString(self.points[::2], cs=self.view.coordsystem)
        style = axipy.Style.from_mapinfo("Pen (1, 2, 0)")
        f_line_str = axipy.Feature(geometry=line_str, style=style)
        feature = f_line_str

        insert_feature(feature)

        axipy.Notifications.push(self.title, self.plugin.tr("Линия успешно добавлена."), axipy.Notifications.Success)


def prepare_to_draw_qt_arc(painter: QPainter, points: List[QPoint]) -> None:
    points = cast(Tuple[QPoint, QPoint, QPoint], points)
    result = center_and_radius_of_circle(points)
    if result is None:
        return None

    center, radius = result
    if radius == 0:
        painter.drawLine(*points[::2])
        return None

    points = cast(List[QPoint], points)
    start_angle, end_angle = start_end_angles(points, center, device=True)

    # Запомнить старый стиль
    pen = painter.pen()
    old_pen = QPen(pen)
    # Задать новый стиль
    pen.setStyle(Qt.DashLine)
    painter.setPen(pen)

    # Нарисовать
    draw_qt_arc(painter, center, radius, start_angle, end_angle, points)

    # Возвратить старый стиль
    painter.setPen(old_pen)


def draw_qt_arc(painter: QPainter, c: axipy.Pnt, r: float, a1: float, a2: float, points: List[QPoint]) -> None:
    max_angle_to_draw_line = 5

    q_point_f = QPointF(c.x - r, c.y - r)
    size = 2 * r
    q_size_f = QSizeF(size, size)
    q_rect_f = QRectF(q_point_f, q_size_f)

    span_angle = a2 - a1
    if span_angle < 0:
        span_angle += 360

    span_angle_int = round(span_angle)

    if span_angle_int <= max_angle_to_draw_line:
        painter.drawLine(*points[::2])
        return None
    qt_span_angle = span_angle_int * 16

    qt_start_angle = round(a1) * 16

    painter.drawArc(q_rect_f, qt_start_angle, qt_span_angle)
