import React, { useRef, useEffect, useCallback } from 'react';

/**
 * KubikonMobileControls — оверлей тач-управления в стиле Roblox mobile.
 *
 * Дизайн:
 *   - Левый низ: полупрозрачный круг 120×120 — джойстик с АНАЛОГОВЫМ
 *     направлением (плавный бег во все стороны, не только 8 секторов).
 *   - Правый низ: одна кнопка прыжка ⬆ — единственная кнопка действия.
 *   - Свайп пальцем по экрану (вне джойстика и кнопки) — поворот камеры
 *     yaw+pitch (как ПКМ на десктопе).
 *   - Короткий ТАП по экрану (без свайпа) — выстрел в направлении камеры.
 *     Так делает большинство шутер-игр Roblox на мобиле.
 */

// Палец прошёл больше TAP_MAX_PX за TAP_MAX_MS — это уже не тап, а свайп.
const TAP_MAX_PX = 10;
const TAP_MAX_MS = 250;

const KubikonMobileControls = ({ getScene }) => {
    // Кружок-джойстик
    const stickBaseRef = useRef(null);
    const stickRef = useRef(null);
    const stickTouchIdRef = useRef(null);

    // Свайп камеры / тап для выстрела
    const cameraTouchIdRef = useRef(null);
    const cameraLastPosRef = useRef({ x: 0, y: 0 });
    const cameraStartRef = useRef({ x: 0, y: 0, t: 0, moved: 0 });

    /** Аналоговый ввод джойстика. Передаём (x, y) ∈ [-1, 1] в PlayerController.
     *  y инвертирован: вверх по экрану = +y = вперёд. */
    const updateJoystick = useCallback((touch) => {
        const base = stickBaseRef.current;
        if (!base) return;
        const rect = base.getBoundingClientRect();
        const cx = rect.left + rect.width / 2;
        const cy = rect.top + rect.height / 2;
        const dx = touch.clientX - cx;
        const dy = touch.clientY - cy;
        const radius = rect.width / 2;
        const dist = Math.hypot(dx, dy);
        const clamped = Math.min(dist, radius);
        const angle = Math.atan2(dy, dx);
        // Knob — визуальный feedback
        const knob = stickRef.current;
        if (knob) {
            const kx = Math.cos(angle) * clamped;
            const ky = Math.sin(angle) * clamped;
            knob.style.transform = `translate(calc(-50% + ${kx}px), calc(-50% + ${ky}px))`;
        }
        // Нормализованный вектор (магнитуда 0..1)
        const nx = dx / radius;
        const ny = dy / radius;
        // Y экрана инвертирован относительно «вперёд»
        const ax = Math.max(-1, Math.min(1, nx));
        const ay = Math.max(-1, Math.min(1, -ny));
        const player = getScene()?.player;
        if (!player) return;
        player.setAnalogMove?.(ax, ay);
        // Sprint при выходе джойстика близко к краю
        player.setVirtualShift?.(Math.hypot(ax, ay) > 0.85);
    }, [getScene]);

    const releaseJoystick = useCallback(() => {
        stickTouchIdRef.current = null;
        const knob = stickRef.current;
        if (knob) knob.style.transform = 'translate(-50%, -50%)';
        const player = getScene()?.player;
        if (player) {
            player.setAnalogMove?.(0, 0);
            player.setVirtualShift?.(false);
        }
    }, [getScene]);

    /** Палец где-то — определяем зону (joystick / button / HUD / scene).
     *  HUD (top-bar, Hotbar, чат) — пропускаем без обработки, чтобы тачи
     *  на их кнопках работали штатно. */
    const onTouchStart = useCallback((e) => {
        for (const t of e.changedTouches) {
            const target = t.target;
            const inJoystick = target.closest?.('[data-mobile-control="joystick"]');
            const inButton = target.closest?.('[data-mobile-control="button"]');
            // HUD-элементы — игнорим (Hotbar, top-bar, чат, заглушки и т.д.).
            // Если palец попал в любой из них — НЕ перехватываем как камеру.
            const inHud = target.closest?.(
                '[data-kubikon-hud], [data-kubikon-top-menu-btn], '
                + '[data-kubikon-top-dropdown], [data-kubikon-bug-btn], '
                + '[data-mobile-hud], button, input, textarea'
            );
            if (inJoystick && stickTouchIdRef.current === null) {
                stickTouchIdRef.current = t.identifier;
                updateJoystick(t);
                e.preventDefault();
                continue;
            }
            if (inButton || inHud) continue;
            // Свободный палец на сцене
            if (cameraTouchIdRef.current === null) {
                cameraTouchIdRef.current = t.identifier;
                cameraLastPosRef.current = { x: t.clientX, y: t.clientY };
                cameraStartRef.current = {
                    x: t.clientX, y: t.clientY,
                    t: Date.now(), moved: 0,
                };
            }
        }
    }, [updateJoystick]);

    const onTouchMove = useCallback((e) => {
        for (const t of e.changedTouches) {
            if (t.identifier === stickTouchIdRef.current) {
                updateJoystick(t);
                e.preventDefault();
            } else if (t.identifier === cameraTouchIdRef.current) {
                const last = cameraLastPosRef.current;
                const dx = t.clientX - last.x;
                const dy = t.clientY - last.y;
                cameraLastPosRef.current = { x: t.clientX, y: t.clientY };
                // Накапливаем общее смещение от старта — для отличия тапа от свайпа
                const start = cameraStartRef.current;
                start.moved = Math.max(start.moved,
                    Math.hypot(t.clientX - start.x, t.clientY - start.y));
                // Если уже свайпнули заметно — крутим камеру
                if (start.moved > TAP_MAX_PX) {
                    getScene()?.player?.addCameraDelta?.(dx, dy);
                }
                e.preventDefault();
            }
        }
    }, [updateJoystick, getScene]);

    const onTouchEnd = useCallback((e) => {
        for (const t of e.changedTouches) {
            if (t.identifier === stickTouchIdRef.current) {
                releaseJoystick();
            } else if (t.identifier === cameraTouchIdRef.current) {
                // Если палец почти не двигался и был на экране < 250мс —
                // считаем это тапом → выстрел в точку тапа.
                const start = cameraStartRef.current;
                const dt = Date.now() - start.t;
                if (start.moved <= TAP_MAX_PX && dt <= TAP_MAX_MS) {
                    const scene = getScene();
                    try {
                        // Tap-to-shoot: передаём canvas-координаты тапа,
                        // WeaponSystem кастует луч из камеры через эту точку.
                        const canvas = scene?.canvas
                            || scene?.engine?.getRenderingCanvas?.();
                        if (canvas && scene?.weapons?.setAimScreenPoint) {
                            const rect = canvas.getBoundingClientRect();
                            // Координаты в CSS-пикселях относительно canvas.
                            // ВАЖНО: на мобилке canvas может быть растянут
                            // (rect.width != canvas.width) — нормализуем
                            // в координаты внутреннего рендер-буфера, иначе
                            // pickingRay улетает не туда.
                            const cssX = t.clientX - rect.left;
                            const cssY = t.clientY - rect.top;
                            const sx = canvas.width  ? cssX * (canvas.width  / rect.width)  : cssX;
                            const sy = canvas.height ? cssY * (canvas.height / rect.height) : cssY;
                            scene.weapons.setAimScreenPoint(sx, sy);
                            // Babylon read scene.pointerX/Y для некоторых
                            // внутренних операций (highlight и т.д.).
                            try {
                                if (scene.scene) {
                                    scene.scene.pointerX = sx;
                                    scene.scene.pointerY = sy;
                                }
                            } catch (e) {}
                        }
                        scene?.weapons?._tryFire?.();
                    } catch (e) {}
                    try { scene?._handlePlayClick?.(); } catch (e) {}
                }
                cameraTouchIdRef.current = null;
            }
        }
    }, [releaseJoystick, getScene]);

    // Глобальный touchend / touchcancel — на случай выхода пальца за overlay
    useEffect(() => {
        const onUp = (e) => onTouchEnd(e);
        window.addEventListener('touchend', onUp);
        window.addEventListener('touchcancel', onUp);
        return () => {
            window.removeEventListener('touchend', onUp);
            window.removeEventListener('touchcancel', onUp);
        };
    }, [onTouchEnd]);

    const overlayRef = useRef(null);
    // Вешаем touch* нативно на WINDOW с {passive:false}.
    // Так мы слышим тачи и в зоне джойстика (overlay, pointer-events:none для
    // корня), и на canvas, и в любой зоне сцены. Bypass для HUD-элементов
    // (Hotbar, top-bar) делается внутри onTouchStart через target.closest:
    // если палец в зоне HUD-элемента — игнорируем (не помечаем как camera-touch).
    useEffect(() => {
        const opts = { passive: false };
        window.addEventListener('touchstart', onTouchStart, opts);
        window.addEventListener('touchmove', onTouchMove, opts);
        window.addEventListener('touchend', onTouchEnd, opts);
        window.addEventListener('touchcancel', onTouchEnd, opts);
        return () => {
            window.removeEventListener('touchstart', onTouchStart, opts);
            window.removeEventListener('touchmove', onTouchMove, opts);
            window.removeEventListener('touchend', onTouchEnd, opts);
            window.removeEventListener('touchcancel', onTouchEnd, opts);
        };
    }, [onTouchStart, onTouchMove, onTouchEnd]);

    // === Присед (hold-to-crouch) ===
    // На touchstart — диспатчим keydown ControlLeft. На touchend — keyup.
    // PlayerController._tick читает this._codes.has('ControlLeft') →
    // включает crouch. Это позволяет проходить под низкими балками.
    const onCrouchStart = useCallback((e) => {
        e.preventDefault?.();
        e.stopPropagation?.();
        try {
            window.dispatchEvent(new KeyboardEvent('keydown', {
                key: 'Control', code: 'ControlLeft',
                keyCode: 17, which: 17, bubbles: true,
            }));
        } catch (e2) { /* ignore */ }
    }, []);
    const onCrouchEnd = useCallback((e) => {
        e.preventDefault?.();
        e.stopPropagation?.();
        try {
            window.dispatchEvent(new KeyboardEvent('keyup', {
                key: 'Control', code: 'ControlLeft',
                keyCode: 17, which: 17, bubbles: true,
            }));
        } catch (e2) { /* ignore */ }
    }, []);

    // === Прыжок ===
    const onJump = useCallback((e) => {
        e.preventDefault?.();
        e.stopPropagation?.();
        getScene()?.player?.triggerJump?.();
        // Шлём пару keydown+keyup 'space' — чтобы скрипты с game.onKey('space')
        // реагировали на кнопку прыжка на мобилке. КРИТИЧНО диспатчить keyup
        // сразу после keydown: иначе Space «залипает» в _codes у Babylon →
        // PlayerController._jumpHeld остаётся true → повторные прыжки не работают.
        try {
            const down = new KeyboardEvent('keydown', {
                key: ' ', code: 'Space', keyCode: 32, which: 32, bubbles: true,
            });
            window.dispatchEvent(down);
            // Через 60мс — keyup, чтобы кнопка считалась «отпущенной»
            setTimeout(() => {
                try {
                    const up = new KeyboardEvent('keyup', {
                        key: ' ', code: 'Space', keyCode: 32, which: 32, bubbles: true,
                    });
                    window.dispatchEvent(up);
                } catch (e3) { /* ignore */ }
            }, 60);
        } catch (e2) { /* ignore */ }
    }, [getScene]);

    // ===== Стили =====
    const glassButton = (size = 64, alpha = 0.30) => ({
        width: size,
        height: size,
        borderRadius: '50%',
        background: `rgba(255, 255, 255, ${alpha})`,
        border: '2px solid rgba(255, 255, 255, 0.55)',
        backdropFilter: 'blur(6px)',
        WebkitBackdropFilter: 'blur(6px)',
        boxShadow: '0 4px 14px rgba(0, 0, 0, 0.30)',
        color: '#fff',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        cursor: 'pointer',
        WebkitTapHighlightColor: 'transparent',
        userSelect: 'none',
        WebkitUserSelect: 'none',
        fontFamily: '"Roboto Condensed", sans-serif',
        fontWeight: 800,
        textShadow: '0 1px 2px rgba(0, 0, 0, 0.6)',
        pointerEvents: 'auto',
    });

    return (
        <div
            ref={overlayRef}
            style={{
                position: 'fixed', inset: 0,
                zIndex: 50,
                touchAction: 'none',
                userSelect: 'none', WebkitUserSelect: 'none',
                WebkitTouchCallout: 'none',
                // Корень overlay — pointer-events: none, чтобы не блокировать
                // тачи на Hotbar / top-bar / других HUD-элементах. Джойстик
                // и кнопка прыжка ниже сами поднимают pointer-events: auto.
                // Camera-свайп и tap-to-shoot вешаются на canvas (не на overlay).
                pointerEvents: 'none',
            }}
        >
            {/* === Джойстик слева === */}
            <div
                ref={stickBaseRef}
                data-mobile-control="joystick"
                style={{
                    position: 'absolute',
                    left: 24, bottom: 24,
                    width: 120, height: 120,
                    borderRadius: '50%',
                    background: 'rgba(255, 255, 255, 0.16)',
                    border: '2px solid rgba(255, 255, 255, 0.45)',
                    backdropFilter: 'blur(6px)',
                    WebkitBackdropFilter: 'blur(6px)',
                    boxShadow: '0 4px 14px rgba(0, 0, 0, 0.30)',
                    pointerEvents: 'auto',
                }}
            >
                <div
                    ref={stickRef}
                    style={{
                        position: 'absolute',
                        left: '50%', top: '50%',
                        width: 48, height: 48,
                        borderRadius: '50%',
                        background: 'rgba(255, 255, 255, 0.85)',
                        boxShadow: '0 2px 8px rgba(0, 0, 0, 0.45)',
                        transform: 'translate(-50%, -50%)',
                        transition: 'transform 0.04s linear',
                        pointerEvents: 'none',
                    }}
                />
            </div>

            {/* === Кнопка прыжка справа === */}
            <button
                data-mobile-control="button"
                aria-label="Прыжок"
                style={{
                    position: 'absolute',
                    right: 28, bottom: 28,
                    ...glassButton(72, 0.32),
                }}
                onTouchStart={onJump}
                onMouseDown={onJump}
            >
                <svg width="34" height="34" viewBox="0 0 24 24" fill="none">
                    <path d="M12 4 L12 20 M5 11 L12 4 L19 11"
                          stroke="#fff" strokeWidth="2.6"
                          strokeLinecap="round" strokeLinejoin="round" />
                </svg>
            </button>
            {/* === Кнопка приседа (hold) — слева от прыжка === */}
            <button
                data-mobile-control="button"
                aria-label="Присед"
                style={{
                    position: 'absolute',
                    right: 110, bottom: 28,
                    ...glassButton(60, 0.28),
                }}
                onTouchStart={onCrouchStart}
                onTouchEnd={onCrouchEnd}
                onTouchCancel={onCrouchEnd}
                onMouseDown={onCrouchStart}
                onMouseUp={onCrouchEnd}
                onMouseLeave={onCrouchEnd}
            >
                <svg width="28" height="28" viewBox="0 0 24 24" fill="none">
                    <path d="M12 20 L12 4 M5 13 L12 20 L19 13"
                          stroke="#fff" strokeWidth="2.6"
                          strokeLinecap="round" strokeLinejoin="round" />
                </svg>
            </button>

            {/* === Подсказка по управлению (исчезает через 5с) === */}
            <HintBubble />
        </div>
    );
};

/** Полупрозрачная подсказка вверху по центру: исчезает через 5 сек. */
const HintBubble = () => {
    const [visible, setVisible] = React.useState(true);
    React.useEffect(() => {
        const t = setTimeout(() => setVisible(false), 5000);
        return () => clearTimeout(t);
    }, []);
    if (!visible) return null;
    return (
        <div style={{
            position: 'absolute',
            top: 'calc(50% + 16px)',
            left: '50%',
            transform: 'translate(-50%, -50%)',
            background: 'rgba(0, 0, 0, 0.55)',
            color: '#fff',
            padding: '10px 16px',
            borderRadius: 999,
            fontSize: 13,
            fontFamily: '"Roboto Condensed", sans-serif',
            fontWeight: 600,
            pointerEvents: 'none',
            textAlign: 'center',
            maxWidth: '80vw',
            opacity: 0.85,
        }}>
            Свайп — повернуть камеру · Тап — выстрел
        </div>
    );
};

export default KubikonMobileControls;
