"""Animierte Hände – wackeln beim Laufen, winken, tanzen."""

from __future__ import annotations

import math
import random
import time

from PyQt6.QtCore import Qt, QRectF
from PyQt6.QtGui import QBrush, QColor, QPainter, QPen

HAND_BODY = (108, 42, 168)
HAND_TINT = (125, 58, 200)
HAND_HIGHLIGHT = (175, 105, 235)


class HandAnimator:
    def __init__(self) -> None:
        self._phase = 0.0
        self._wave_until = 0.0
        self._idle_wave_at = time.time() + random.uniform(4.0, 9.0)

    def tick(self, *, moving: bool, dancing: bool) -> None:
        now = time.time()
        if dancing:
            self._phase += 0.24
        elif moving:
            self._phase += 0.16
        else:
            self._phase += 0.045
            if now >= self._idle_wave_at:
                self._wave_until = now + 1.6
                self._idle_wave_at = now + random.uniform(9.0, 18.0)

    def _pose(
        self,
        *,
        left: bool,
        moving: bool,
        dancing: bool,
        step: float,
    ) -> tuple[float, float, float]:
        """Winkel (Grad), Armlänge-Faktor, Hebung (0–1 relativ zur Körperhöhe)."""
        side = -1.0 if left else 1.0
        p = self._phase
        now = time.time()

        if dancing:
            angle = side * (8.0 + math.sin(p * 2.4 + (0.0 if left else math.pi)) * 48.0)
            lift = 0.1 + max(0.0, math.sin(p * 2.6 + side * 0.5)) * 0.2
            reach = 0.42
        elif moving:
            swing = step * 34.0
            angle = side * 14.0 - swing * side
            lift = 0.02 + abs(step) * 0.02
            reach = 0.36
        elif now < self._wave_until:
            if left:
                angle = side * 28.0 + math.sin(p * 0.8) * 4.0
                lift = 0.03
                reach = 0.3
            else:
                angle = side * (-52.0 + math.sin(p * 7.5) * 22.0)
                lift = 0.06 + max(0.0, math.sin(p * 6.0)) * 0.24
                reach = 0.4
        else:
            angle = side * (24.0 + math.sin(p * 0.85) * 7.0)
            lift = math.sin(p * 0.65) * 0.035
            reach = 0.33

        return angle, reach, lift

    def draw(
        self,
        p: QPainter,
        body: QRectF,
        *,
        face_left: bool,
        moving: bool,
        dancing: bool,
        step: float = 0.0,
        tint: tuple[int, int, int] | None = None,
    ) -> None:
        if body.width() < 24:
            return

        base = tint or HAND_BODY
        mid = (
            min(255, int(base[0] * 0.9 + HAND_TINT[0] * 0.1)),
            min(255, int(base[1] * 0.9 + HAND_TINT[1] * 0.1)),
            min(255, int(base[2] * 0.9 + HAND_TINT[2] * 0.1)),
        )
        hi = (
            min(255, mid[0] + 45),
            min(255, mid[1] + 40),
            min(255, mid[2] + 35),
        )

        bw, bh = body.width(), body.height()
        hand_r = bw * 0.055

        for left in (True, False):
            angle, reach, raise_amt = self._pose(
                left=left, moving=moving, dancing=dancing, step=step
            )
            if face_left:
                angle = -angle

            if left:
                sx = body.x() + bw * 0.12
            else:
                sx = body.x() + bw * 0.88
            sy = body.y() + bh * (0.5 - raise_amt)
            arm_len = bh * reach

            p.save()
            p.translate(sx, sy)
            p.rotate(angle)

            p.setPen(QPen(QColor(55, 18, 85, 90), max(1, int(hand_r * 0.15))))
            p.setBrush(QBrush(QColor(*mid)))
            stub_w = hand_r * 1.35
            stub_h = arm_len * 0.52
            p.drawRoundedRect(
                QRectF(-stub_w * 0.45, -stub_h * 0.15, stub_w, stub_h),
                stub_w * 0.4,
                stub_w * 0.4,
            )

            p.setPen(Qt.PenStyle.NoPen)
            p.setBrush(QBrush(QColor(*hi)))
            hy = stub_h * 0.72
            p.drawEllipse(
                int(-hand_r),
                int(hy - hand_r),
                int(hand_r * 2),
                int(hand_r * 2.15),
            )
            for dx in (-0.55, 0.0, 0.55):
                p.drawEllipse(
                    int(dx * hand_r - hand_r * 0.28),
                    int(hy + hand_r * 0.55),
                    int(hand_r * 0.56),
                    int(hand_r * 0.5),
                )
            p.restore()
