import React, { useEffect, useState, useRef } from 'react';
import * as Kubikon3DApi from '../../api/Kubikon3DService';

// Тег версии оптимизации — менять при каждом этапе чтобы фильтровать логи.
const BUILD_TAG = 'diag-2';

const round2 = (v) => Math.round(v * 100) / 100;

/**
 * KubikonPerfOverlay — лёгкий performance-monitor для Play-режима Кубикона.
 *
 * Показывает в левом нижнем углу:
 *   FPS, frame-time, draw-calls, active meshes, total meshes, RAM, GPU.
 *
 * Включается/выключается клавишей F или кликом по компактному бейджу.
 * По умолчанию ВЫКЛЮЧЕН — чтобы не мешать игроку.
 *
 * Props:
 *   getScene — функция возвращающая BabylonScene (sceneRef.current)
 *   visible — внешний контроль видимости (если null/undefined — internal toggle через F)
 */
export default function KubikonPerfOverlay({ getScene, projectId, userId }) {
    const [open, setOpen] = useState(false);
    const [stats, setStats] = useState({
        fps: 0,
        frameMs: 0,
        drawCalls: 0,
        activeMeshes: 0,
        totalMeshes: 0,
        memMB: null,
        memLimitMB: null,
        gpu: '',
        mobile: false,
    });
    const rafRef = useRef(null);
    const lastSampleRef = useRef(performance.now());
    const framesRef = useRef(0);
    const lastFpsRef = useRef(0);
    const lastFrameTimeRef = useRef(0);
    const gpuInfoRef = useRef(null);

    // ====================================================================
    // ФОНОВЫЙ СЭМПЛЕР: всегда работает в Play-режиме (даже если overlay
    // закрыт). Раз в 5 секунд агрегирует и отправляет на бэк.
    // ====================================================================
    useEffect(() => {
        if (!projectId) return;
        let cancelled = false;
        let frames = 0;
        let frameMsSum = 0;
        let drawCallsSum = 0;
        let activeMeshesSum = 0;
        let totalMeshes = 0;
        let fpsMin = Infinity;
        let fpsMax = 0;
        let lastFrameTs = performance.now();
        let windowStart = performance.now();
        let raf = null;

        // Кэш окружения — не пересчитываем каждый кадр
        let envCache = null;
        const getEnv = () => {
            if (envCache) return envCache;
            try {
                const scene = getScene?.();
                let gpu = '';
                let mobile = false;
                if (scene?.engine?._gl) {
                    const dbg = scene.engine._gl.getExtension('WEBGL_debug_renderer_info');
                    if (dbg) {
                        gpu = String(scene.engine._gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) || '').slice(0, 200);
                    }
                }
                if (scene && '_isMobileMode' in scene) mobile = !!scene._isMobileMode;
                envCache = {
                    gpu,
                    mobile,
                    ua: (navigator?.userAgent || '').slice(0, 400),
                    screen_w: window.innerWidth,
                    screen_h: window.innerHeight,
                    dpr: window.devicePixelRatio || 1,
                };
            } catch (e) {
                envCache = { gpu: '', mobile: false, ua: '', screen_w: 0, screen_h: 0, dpr: 1 };
            }
            return envCache;
        };

        const flush = () => {
            if (frames < 5) {
                // Слишком мало кадров — скип
                return;
            }
            const elapsed = performance.now() - windowStart;
            const fpsAvg = (frames * 1000) / elapsed;
            const frameMsAvg = frameMsSum / frames;
            const drawCallsAvg = drawCallsSum / frames;
            const activeMeshesAvg = activeMeshesSum / frames;
            const env = getEnv();
            // PERF-METRICS: забираем и сбрасываем накопленные за окно метрики
            let perfM = null;
            try {
                const scene = getScene?.();
                if (scene?.flushPerfMetrics) perfM = scene.flushPerfMetrics();
            } catch (e) { /* ignore */ }
            const sample = {
                user_id: userId || null,
                project_id: projectId,
                fps_avg: round2(fpsAvg),
                fps_min: round2(fpsMin === Infinity ? 0 : fpsMin),
                fps_max: round2(fpsMax),
                frame_ms_avg: round2(frameMsAvg),
                draw_calls_avg: round2(drawCallsAvg),
                active_meshes_avg: round2(activeMeshesAvg),
                total_meshes: totalMeshes || 0,
                mem_mb: performance.memory
                    ? Math.round(performance.memory.usedJSHeapSize / 1048576)
                    : null,
                mem_limit_mb: performance.memory
                    ? Math.round(performance.memory.jsHeapSizeLimit / 1048576)
                    : null,
                ...env,
                sample_count: frames,
                build_tag: BUILD_TAG,
                render_ms_avg: perfM ? round2(perfM.render_ms_avg) : null,
                physics_ms_avg: perfM ? round2(perfM.physics_ms_avg) : null,
                script_ms_avg: perfM ? round2(perfM.script_ms_avg) : null,
                script_count: perfM ? perfM.script_count : null,
                idle_ms_avg: perfM ? round2(perfM.idle_ms_avg) : null,
            };
            // Шлём fire-and-forget
            Kubikon3DApi.submitPerfLog(sample).catch(() => { /* ignore */ });

            // Сброс окна
            frames = 0;
            frameMsSum = 0;
            drawCallsSum = 0;
            activeMeshesSum = 0;
            fpsMin = Infinity;
            fpsMax = 0;
            windowStart = performance.now();
        };

        const tick = () => {
            if (cancelled) return;
            const now = performance.now();
            const dt = now - lastFrameTs;
            lastFrameTs = now;
            // FPS на отдельном кадре (для min/max)
            if (dt > 0) {
                const instFps = 1000 / dt;
                if (instFps < fpsMin) fpsMin = instFps;
                if (instFps > fpsMax) fpsMax = instFps;
            }
            frames++;
            // Снапшот метрик
            try {
                const scene = getScene?.();
                if (scene) {
                    const eng = scene.engine;
                    const sc = scene.scene;
                    if (eng) {
                        frameMsSum += eng.getDeltaTime?.() || dt;
                        drawCallsSum += (eng.drawCallsCounter?.current
                            || eng._drawCalls?.current || 0);
                    }
                    if (sc) {
                        activeMeshesSum += (sc.getActiveMeshes?.()?.length || 0);
                        totalMeshes = sc.meshes?.length || 0;
                    }
                }
            } catch (e) { /* ignore */ }

            // Раз в 5 сек — flush
            if (now - windowStart >= 5000) {
                flush();
            }
            raf = requestAnimationFrame(tick);
        };
        raf = requestAnimationFrame(tick);
        return () => {
            cancelled = true;
            if (raf) cancelAnimationFrame(raf);
            // Финальный flush при unmount (если что-то накопилось)
            try { flush(); } catch (e) { /* ignore */ }
        };
    }, [projectId, userId, getScene]);

    // Тоггл по F
    useEffect(() => {
        const onKey = (e) => {
            if (e.code !== 'KeyF') return;
            // Не перехватываем если фокус в input
            const tag = (e.target && e.target.tagName) || '';
            if (tag === 'INPUT' || tag === 'TEXTAREA') return;
            // Не должно конфликтовать с Ctrl+F (поиск)
            if (e.ctrlKey || e.metaKey || e.altKey) return;
            setOpen(v => !v);
        };
        window.addEventListener('keydown', onKey);
        return () => window.removeEventListener('keydown', onKey);
    }, []);

    // Измерение FPS и сбор статистики
    useEffect(() => {
        if (!open) return;
        let cancelled = false;

        const tick = () => {
            if (cancelled) return;
            framesRef.current++;
            const now = performance.now();
            const elapsed = now - lastSampleRef.current;
            // Раз в ~500мс обновляем стейт (чтобы не ререндерить 60 раз/сек)
            if (elapsed >= 500) {
                const fps = (framesRef.current * 1000) / elapsed;
                lastFpsRef.current = fps;
                framesRef.current = 0;
                lastSampleRef.current = now;

                // Babylon Engine + Scene статистика
                const scene = getScene?.();
                let drawCalls = 0;
                let activeMeshes = 0;
                let totalMeshes = 0;
                let frameMs = 0;
                let mobile = false;
                if (scene) {
                    try {
                        const eng = scene.engine;
                        const sc = scene.scene;
                        if (eng) {
                            drawCalls = eng.drawCallsCounter?.current
                                || eng._drawCalls?.current
                                || 0;
                            // getDeltaTime в мс
                            frameMs = eng.getDeltaTime?.() || 0;
                            lastFrameTimeRef.current = frameMs;
                            // GPU info один раз
                            if (!gpuInfoRef.current) {
                                try {
                                    const gl = eng._gl;
                                    if (gl) {
                                        const dbgRendererInfo = gl.getExtension('WEBGL_debug_renderer_info');
                                        if (dbgRendererInfo) {
                                            gpuInfoRef.current = String(
                                                gl.getParameter(dbgRendererInfo.UNMASKED_RENDERER_WEBGL)
                                                || ''
                                            ).slice(0, 60);
                                        }
                                    }
                                } catch (e) { /* ignore */ }
                                if (!gpuInfoRef.current) gpuInfoRef.current = '?';
                            }
                        }
                        if (sc) {
                            activeMeshes = sc.getActiveMeshes?.()?.length || 0;
                            totalMeshes = sc.meshes?.length || 0;
                        }
                        mobile = !!scene._isMobileMode;
                    } catch (e) { /* ignore */ }
                }

                // Memory (Chrome only)
                let memMB = null;
                let memLimitMB = null;
                if (performance.memory) {
                    memMB = Math.round(performance.memory.usedJSHeapSize / 1048576);
                    memLimitMB = Math.round(performance.memory.jsHeapSizeLimit / 1048576);
                }

                setStats({
                    fps: Math.round(fps),
                    frameMs: lastFrameTimeRef.current,
                    drawCalls,
                    activeMeshes,
                    totalMeshes,
                    memMB,
                    memLimitMB,
                    gpu: gpuInfoRef.current || '?',
                    mobile,
                });
            }
            rafRef.current = requestAnimationFrame(tick);
        };
        rafRef.current = requestAnimationFrame(tick);
        return () => {
            cancelled = true;
            if (rafRef.current) cancelAnimationFrame(rafRef.current);
        };
    }, [open, getScene]);

    // Цвет FPS — индикация качества
    const fpsColor = stats.fps >= 55 ? '#22d97a'
        : stats.fps >= 30 ? '#ffd700'
        : '#ff5e3a';

    // Маленький бейдж когда закрыто — РИГТ-БОТТОМ, не мешает HUD сверху
    if (!open) {
        return (
            <button
                onClick={() => setOpen(true)}
                title="Открыть FPS-монитор (F)"
                style={{
                    position: 'absolute',
                    bottom: 12, right: 12,
                    zIndex: 40,
                    padding: '6px 10px',
                    background: 'rgba(20, 24, 45, 0.85)',
                    border: '1px solid rgba(255, 255, 255, 0.18)',
                    borderRadius: 8,
                    color: 'rgba(255, 255, 255, 0.7)',
                    fontFamily: 'ui-monospace, "SF Mono", Menlo, monospace',
                    fontSize: 11, fontWeight: 700,
                    cursor: 'pointer',
                    backdropFilter: 'blur(6px)',
                    pointerEvents: 'auto',
                    opacity: 0.55,
                    transition: 'opacity 200ms ease',
                }}
                onMouseEnter={(e) => { e.currentTarget.style.opacity = '1'; }}
                onMouseLeave={(e) => { e.currentTarget.style.opacity = '0.55'; }}
            >📊 FPS</button>
        );
    }

    return (
        <div style={{
            position: 'absolute',
            bottom: 12, right: 12,
            zIndex: 40,
            background: 'rgba(10, 14, 26, 0.92)',
            border: '1px solid rgba(255, 255, 255, 0.10)',
            borderRadius: 10,
            color: '#f1f5fb',
            fontFamily: 'ui-monospace, "SF Mono", Menlo, monospace',
            fontSize: 11, lineHeight: 1.5,
            padding: '8px 12px',
            backdropFilter: 'blur(10px)',
            boxShadow: '0 8px 22px rgba(0,0,0,0.4)',
            minWidth: 200,
            pointerEvents: 'auto',
            animation: 'kubikonFadeIn 200ms ease',
        }}>
            <div style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                marginBottom: 6,
            }}>
                <span style={{ fontWeight: 800, color: '#3357ff', fontSize: 11 }}>
                    📊 PERF
                </span>
                <button
                    onClick={() => setOpen(false)}
                    title="Скрыть (F)"
                    style={{
                        background: 'transparent', border: 'none',
                        color: 'rgba(255,255,255,0.5)', cursor: 'pointer',
                        fontSize: 14, padding: '0 4px', lineHeight: 1,
                    }}
                >✕</button>
            </div>
            <Row label="FPS" value={
                <span style={{ color: fpsColor, fontWeight: 800 }}>
                    {stats.fps}
                </span>
            } />
            <Row label="frame" value={`${stats.frameMs.toFixed(1)} ms`} />
            <Row label="draw calls" value={stats.drawCalls} />
            <Row label="meshes" value={`${stats.activeMeshes} / ${stats.totalMeshes}`} />
            {stats.memMB != null && (
                <Row label="JS heap" value={
                    `${stats.memMB} / ${stats.memLimitMB} MB`
                } />
            )}
            <Row label="mode" value={
                <span style={{
                    color: stats.mobile ? '#ec4899' : '#22d97a',
                    fontWeight: 700,
                }}>
                    {stats.mobile ? '📱 MOBILE' : '🖥️ DESKTOP'}
                </span>
            } />
            <div style={{
                marginTop: 6, paddingTop: 6,
                borderTop: '1px solid rgba(255,255,255,0.08)',
                fontSize: 10, color: 'rgba(255,255,255,0.55)',
                wordBreak: 'break-word',
            }}>
                GPU: {stats.gpu}
            </div>
        </div>
    );
}

const Row = ({ label, value }) => (
    <div style={{
        display: 'flex', justifyContent: 'space-between',
        gap: 12,
    }}>
        <span style={{ color: 'rgba(255,255,255,0.55)' }}>{label}</span>
        <span>{value}</span>
    </div>
);
