#!/usr/bin/env python3
"""
Феджи-сторож 2.8 — консольный спам, важные контакты, детектор резких движений ушей и хвоста.
"""
from pythonosc import dispatcher, osc_server
import subprocess
import time

LISTEN_IP = "127.0.0.1"
LISTEN_PORT = 9001

# ---------- Настройки ----------
# Пороги для рывков (чем меньше, тем чувствительнее)
EAR_JERK_THRESHOLD = 0.291     # ухо дёрнули
TAIL_JERK_THRESHOLD = 0.8    # хвост резко вильнул/дёрнули

# Что ВЫВОДИТЬ В КОНСОЛЬ (можно всё подряд)
LOG_PARAMS = {
    "Touch/Head": "float",
    "Touch/CheekL": "float",
    "Touch/CheekR": "float",
    "Touch/Nose": "float",
    "Cheese/Slap": "float",
    "Mayu/HeadPurr": "bool",
    "Mayu/BellyPurr": "bool",
    "Mayu/FeetPurr": "bool",
    "Mayu/CheeseReceiver": "bool",
    "Mayu/CheeseSender": "bool",
    "Tail/_IsGrabbed": "bool",
    "Tail/_Stretch": "float",
    "Ear/Left_Angle": "float",
    "Ear/Right_Angle": "float",
}

# Что ПОКАЗЫВАТЬ В УВЕДОМЛЕНИЯХ (важные контакты)
NOTIFY_IMPORTANT = {
    "Touch/Head": "float",
    "Touch/CheekL": "float",
    "Touch/CheekR": "float",
    "Touch/Nose": "float",
    "Cheese/Slap": "float",
    "Mayu/HeadPurr": "bool",
    "Mayu/BellyPurr": "bool",
    "Mayu/FeetPurr": "bool",
    "Tail/_IsGrabbed": "bool",
}

NOTIFY_COOLDOWN = 3.0  # секунды между любыми уведомлениями

# ---------- Состояние ----------
prev_ear_left = None
prev_ear_right = None
prev_tail_angle = None
last_notify = 0

def notify(title, msg):
    subprocess.call(["notify-send", title, msg, "--icon=vrchat"])

def handle_osc(address, *args):
    global prev_ear_left, prev_ear_right, prev_tail_angle, last_notify
    value = args[0] if args else None
    if value is None:
        return

    PREFIX = "/avatar/parameters/"
    if not address.startswith(PREFIX):
        return
    param = address[len(PREFIX):]

    # --- ЛОГИРОВАНИЕ В КОНСОЛЬ (почти всё) ---
    if param in LOG_PARAMS:
        ptype = LOG_PARAMS[param]
        if ptype == "bool" and isinstance(value, bool):
            print(f"🟢 [LOG] {param} = {value}")
        elif ptype == "float" and isinstance(value, (int, float)):
            if value != 0.0:  # уменьшаем мусор от нулей
                print(f"🔵 [LOG] {param} = {value:.4f}")

    now = time.time()

    # --- УВЕДОМЛЕНИЯ О ВАЖНЫХ КОНТАКТАХ ---
    if param in NOTIFY_IMPORTANT:
        ptype = NOTIFY_IMPORTANT[param]
        triggered = False
        if ptype == "bool" and isinstance(value, bool) and value:
            triggered = True
        elif ptype == "float" and isinstance(value, (int, float)) and value > 0.0:
            triggered = True

        if triggered and (now - last_notify >= NOTIFY_COOLDOWN):
            if param == "Tail/_IsGrabbed":
                notify("🦊 Хвост в плену!", "Кто-то схватил и держит хвост!")
            else:
                notify("🦊 Важное прикосновение!", f"{param} = {value}")
            print(f"🔔 [УВЕДОМЛЕНИЕ] {param} = {value}")
            last_notify = now
            return  # не проверяем рывки в этом же пакете

    # --- ДЕТЕКТОР РЕЗКИХ ДВИЖЕНИЙ (уши и хвост) ---
    # Уши
    if param == "Ear/Left_Angle" and isinstance(value, (float, int)):
        if prev_ear_left is not None:
            diff = abs(value - prev_ear_left)
            if diff > EAR_JERK_THRESHOLD and (now - last_notify >= NOTIFY_COOLDOWN):
                notify("🦊 Левое ухо дёрнули!", f"Рывок: {diff:.3f}")
                print(f"🔔 [РЫВОК] {param} = {value:.4f} (Δ={diff:.3f})")
                last_notify = now
        prev_ear_left = value

    elif param == "Ear/Right_Angle" and isinstance(value, (float, int)):
        if prev_ear_right is not None:
            diff = abs(value - prev_ear_right)
            if diff > EAR_JERK_THRESHOLD and (now - last_notify >= NOTIFY_COOLDOWN):
                notify("🦊 Правое ухо дёрнули!", f"Рывок: {diff:.3f}")
                print(f"🔔 [РЫВОК] {param} = {value:.4f} (Δ={diff:.3f})")
                last_notify = now
        prev_ear_right = value

    # Хвост (угол)
    elif param == "Tail/_Angle" and isinstance(value, (float, int)):
        if prev_tail_angle is not None:
            diff = abs(value - prev_tail_angle)
            if diff > TAIL_JERK_THRESHOLD and (now - last_notify >= NOTIFY_COOLDOWN):
                notify("🦊 Хвост резко вильнул!", f"Рывок: {diff:.3f}")
                print(f"🔔 [РЫВОК] {param} = {value:.4f} (Δ={diff:.3f})")
                last_notify = now
        prev_tail_angle = value

if __name__ == "__main__":
    disp = dispatcher.Dispatcher()
    disp.map("/avatar/parameters/*", handle_osc)

    print("🦊 Феджи-сторож 2.8 активирован.")
    print("Консольный спам:", list(LOG_PARAMS.keys()))
    print("Уведомления (контакты + рывки):", list(NOTIFY_IMPORTANT.keys()))
    print("Пороги рывков: уши >", EAR_JERK_THRESHOLD, ", хвост >", TAIL_JERK_THRESHOLD)
    server = osc_server.ThreadingOSCUDPServer((LISTEN_IP, LISTEN_PORT), disp)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\n🦊 Всё, сворачиваюсь. Пусть уши будут целы, Реджик!")
