import React, { useEffect, useRef, useState, useCallback } from 'react';
import { Link } from 'react-router-dom';
import { jwtDecode } from 'jwt-decode';
import { io } from 'socket.io-client';
import * as Kubikon3DApi from '../api/Kubikon3DService';
import { STORYS_addres } from '../api/API';
import { formatTimeShort } from '../utils/kubikonTime';
import EmailConfirmNotice from '../components/EmailConfirmNotice/EmailConfirmNotice';

/**
 * KubikonChatPanel — внутриигровой WebSocket-чат для опубликованной игры.
 *
 * Транспорт: Socket.IO, namespace /kubikon3d/chat, комната project_<id>.
 * Если WS не установился (proxy режется, brownfield-сеть) — падаем на REST polling.
 *
 * События WS:
 *   ← chat:hello       { last_id, online, messages, is_guest }
 *   ← chat:message     { id, project_id, user_id, username, text, created_at, ... }
 *   ← chat:online      { count }
 *   ← chat:muted       { banned_until, reason, is_manual }
 *   ← chat:error       { message, reason? }
 *
 * Props: projectId, onClose, onRequestAuth(action)
 */
const POLL_INTERVAL_MS = 3000;
const WS_FAILOVER_AFTER_MS = 4000;   // если за 4с не подсоединились — переходим на polling

/**
 * Если передан `realtimeRoom` (Colyseus.js Room из мультиплеера) — чат идёт
 * через него, без обращения к storys-микросервису. Это режим in-game чата:
 *   • видны только сообщения игроков ИЗ ЭТОЙ КОМНАТЫ (не глобальный чат игры)
 *   • без истории — новые подключившиеся видят только сообщения с момента
 *     подключения
 *   • без мьютов / модерации (комната живёт минуты, пока есть игроки)
 *
 * Если `realtimeRoom` НЕ передан — старая логика (Socket.IO к storys).
 */
const KubikonChatPanel = ({ projectId, onClose, onRequestAuth, compact = false, realtimeRoom = null, mobileMode = false }) => {
    const [messages, setMessages] = useState([]);
    const [text, setText] = useState('');
    const [submitting, setSubmitting] = useState(false);
    const [error, setError] = useState(null);
    const [muteInfo, setMuteInfo] = useState(null);    // активный мьют
    const [loaded, setLoaded] = useState(false);
    const [online, setOnline] = useState(0);
    const [transport, setTransport] = useState('connecting');   // 'ws' | 'polling' | 'connecting' | 'realtime'
    const [emailNotice, setEmailNotice] = useState(false);   // окно «подтвердите email»

    const lastIdRef = useRef(0);
    const listRef = useRef(null);
    const socketRef = useRef(null);
    // onRequestAuth от родителя — стабилизируем через ref, чтобы он не попадал
    // в deps useEffect и не вызывал re-mount (=пересоздание WS) каждый рендер.
    const onRequestAuthRef = useRef(onRequestAuth);
    useEffect(() => { onRequestAuthRef.current = onRequestAuth; }, [onRequestAuth]);

    const userInfo = (() => {
        try {
            const raw = localStorage.getItem('Authorization');
            if (!raw) return null;
            const token = raw.startsWith('Bearer ') ? raw.slice(7).trim() : raw.trim();
            if (!token) return null;
            const p = jwtDecode(token);
            // Гостевой токен — не считается авторизованным пользователем.
            const isGuest = p?.guest === true
                || (typeof p?.sub === 'string' && p.sub.startsWith('guest_'))
                || p?.type === 'guest';
            if (isGuest) return null;
            const id = p?.id ?? p?.user_id ?? p?.userId ?? null;
            return {
                id: id != null ? Number(id) || null : null,
                username: p?.firstName || p?.first_name || p?.email || '',
            };
        } catch (e) { return null; }
    })();
    const userId = userInfo?.id || null;

    // === Realtime-чат (Colyseus room) ===
    // Если родитель передал realtimeRoom — используем его, не идём в storys.
    useEffect(() => {
        if (!realtimeRoom) return;
        setTransport('realtime');
        setLoaded(true);
        setOnline(realtimeRoom.state?.players?.size || 0);

        const offChat = realtimeRoom.onMessage('chat', (msg) => {
            setMessages(prev => [
                ...prev,
                {
                    id: Date.now() + Math.random(),
                    user_id: msg.userId,
                    username: msg.username,
                    text: msg.text,
                    created_at: new Date(msg.ts).toISOString(),
                    transport: 'realtime',
                },
            ].slice(-200));   // последние 200, не копим бесконечно
        });
        const offRejected = realtimeRoom.onMessage('chat-rejected', (m) => {
            setError(m.text || 'Сообщение не отправлено');
        });

        // Online-counter обновляется когда игроки заходят/выходят.
        // Подсчитываем через state.players через простой interval — точнее,
        // подписаться можно через getStateCallbacks, но нам достаточно опроса.
        const t = setInterval(() => {
            setOnline(realtimeRoom.state?.players?.size || 0);
        }, 1000);

        return () => {
            try { offChat?.(); } catch (e) {}
            try { offRejected?.(); } catch (e) {}
            clearInterval(t);
        };
    }, [realtimeRoom]);

    // === Socket.IO — fallback для не-мультиплеерных игр ===
    // Если WS не подключится за WS_FAILOVER_AFTER_MS, включится polling-fallback.
    useEffect(() => {
        // Если работаем в realtime-режиме — Socket.IO не нужен
        if (realtimeRoom) return;

        let alive = true;
        let pollTimer = null;
        let failoverTimer = null;

        const tokenRaw = localStorage.getItem('Authorization') || '';
        const token = tokenRaw.startsWith('Bearer ') ? tokenRaw.slice(7) : tokenRaw;

        // socket.io-client особенность: при io(url, opts) — из url берётся ТОЛЬКО
        // origin + namespace (последний сегмент). Префикс пути отбрасывается, и
        // используется ровно opts.path. Поэтому передаём:
        //   1) origin + namespace в URL
        //   2) полный путь /api-storys/socket.io в opts.path
        // Извлекаем origin из STORYS_addres (например https://dev-api.rublox.pro/api-storys)
        let storysOrigin;
        let storysPath;
        try {
            const u = new URL(STORYS_addres);
            storysOrigin = u.origin;                                // https://dev-api.rublox.pro
            storysPath = (u.pathname || '').replace(/\/$/, '') + '/socket.io';
        } catch (e) {
            // Fallback (на случай dev-сборки без полного URL)
            storysOrigin = STORYS_addres;
            storysPath = '/socket.io';
        }

        const socket = io(storysOrigin + '/kubikon3d/chat', {
            path: storysPath,
            transports: ['websocket'],
            query: { project: projectId, token },
            forceNew: true,
            reconnection: true,
            reconnectionAttempts: 3,
            reconnectionDelay: 1000,
        });
        socketRef.current = socket;

        // Если за N секунд WS не подключилось — переходим на polling
        failoverTimer = setTimeout(() => {
            if (!alive) return;
            if (!socket.connected) {
                setTransport('polling');
                startPolling();
            }
        }, WS_FAILOVER_AFTER_MS);

        socket.on('connect', () => {
            if (!alive) return;
            setTransport('ws');
            clearTimeout(failoverTimer);
            // Polling больше не нужен
            if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }
        });

        socket.on('chat:hello', (payload) => {
            if (!alive) return;
            const msgs = payload?.messages || [];
            setMessages(msgs);
            lastIdRef.current = payload?.last_id || 0;
            setOnline(payload?.online || 0);
            setLoaded(true);
        });

        socket.on('chat:message', (msg) => {
            if (!alive) return;
            setMessages(prev => {
                // Защита от дублей (если REST-fallback уже добавил)
                if (prev.some(x => x.id === msg.id)) return prev;
                return [...prev, msg];
            });
            lastIdRef.current = Math.max(lastIdRef.current, msg.id);
        });

        socket.on('chat:online', (payload) => {
            if (!alive) return;
            setOnline(payload?.count || 0);
        });

        socket.on('chat:muted', (payload) => {
            if (!alive) return;
            setMuteInfo({
                banned_until: payload?.banned_until,
                last_reason: payload?.reason,
                is_manual: payload?.is_manual,
            });
        });

        socket.on('chat:error', (payload) => {
            if (!alive) return;
            const m = payload?.message || 'error';
            if (m === 'login_required') onRequestAuthRef.current?.('писать в чат');
            else if (m === 'email_not_confirmed') setEmailNotice(true);
            else if (m === 'too_frequent') setError(payload?.text || 'Слишком быстро.');
            else if (m === 'invalid_text') setError('Сообщение пустое.');
            else setError(payload?.text || m);
        });

        socket.on('disconnect', () => {
            if (!alive) return;
            setTransport('connecting');
        });

        socket.on('connect_error', () => {
            // не падаем сразу — failoverTimer переключит на polling
        });

        // === Polling-fallback ===
        // Для draft-проектов чат недоступен (бэкенд отвечает 403). В этом
        // случае НЕ запускаем интервал — иначе он будет каждые 3с отправлять
        // HTTP-запрос с 403, что блокирует main thread и виден дёрганый
        // куб игрока в GD-уровнях (см. отчёт 2026-05-19).
        const startPolling = async () => {
            if (pollTimer) return;
            let initialFailedAsForbidden = false;
            try {
                const res = await Kubikon3DApi.getChat(projectId);
                if (!alive) return;
                setMessages(res.data?.messages || []);
                lastIdRef.current = res.data?.last_id || 0;
                setLoaded(true);
            } catch (e) {
                // 403 = project_not_published. Дальнейший polling бессмысленен.
                if (e?.response?.status === 403) {
                    initialFailedAsForbidden = true;
                    setLoaded(true);   // не висим в «загрузка...» бесконечно
                }
            }
            if (initialFailedAsForbidden) return;
            pollTimer = setInterval(async () => {
                if (!alive) return;
                try {
                    const res = await Kubikon3DApi.getChat(projectId, lastIdRef.current);
                    const newMsgs = res.data?.messages || [];
                    if (newMsgs.length > 0) {
                        setMessages(prev => [...prev, ...newMsgs]);
                        lastIdRef.current = res.data.last_id;
                    }
                } catch (e) {
                    // Если стал 403 в процессе (например, статус сменился на draft) —
                    // прекращаем polling, чтобы не флудить пустыми запросами.
                    if (e?.response?.status === 403 && pollTimer) {
                        clearInterval(pollTimer);
                        pollTimer = null;
                    }
                }
            }, POLL_INTERVAL_MS);
        };

        // Параллельно проверяем mute-статус (REST), независимо от транспорта
        if (userId) {
            Kubikon3DApi.getChatMuteStatus(userId)
                .then(r => { if (alive && r.data?.muted) setMuteInfo(r.data.ban); })
                .catch(() => {});
        }

        return () => {
            alive = false;
            clearTimeout(failoverTimer);
            if (pollTimer) clearInterval(pollTimer);
            try { socket.disconnect(); } catch (e) {}
            socketRef.current = null;
        };
    // ВАЖНО: onRequestAuth НЕ в deps — он берётся из ref. Иначе при каждом
    // рендере родителя useEffect пересобирался бы и пересоздавал WS-соединение.
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [projectId, userId]);

    // Автоскролл вниз: при первой загрузке скроллим всегда. При новых сообщениях
    // — только если пользователь сам не отскроллил вверх (>200px от низа).
    // Используем двойной RAF — фактический scrollHeight доступен только после
    // того как браузер применил layout новых сообщений.
    const wasFirstScrollRef = useRef(false);
    useEffect(() => {
        const el = listRef.current;
        if (!el) return;
        const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
        const isFirst = !wasFirstScrollRef.current && messages.length > 0;
        const stayDown = isFirst || distanceFromBottom < 200;
        if (stayDown) {
            requestAnimationFrame(() => {
                requestAnimationFrame(() => {
                    if (listRef.current) {
                        listRef.current.scrollTop = listRef.current.scrollHeight;
                    }
                });
            });
            if (isFirst) wasFirstScrollRef.current = true;
        }
    }, [messages, loaded]);

    const send = async () => {
        if (!userId) { onRequestAuth?.('писать в чат'); return; }
        const t = text.trim();
        if (!t) return;
        setError(null);

        // === Путь 0: Realtime (Colyseus room) ===
        // Если в этом сеансе есть multiplayer-room, шлём через неё.
        if (realtimeRoom) {
            try {
                realtimeRoom.send('chat', { text: t });
                setText('');
            } catch (e) {
                setError('Ошибка отправки в realtime');
            }
            return;
        }

        const sock = socketRef.current;
        // === Путь 1: WebSocket ===
        if (sock && sock.connected) {
            sock.emit('chat:send', {
                text: t,
                username: userInfo?.username || '',
            });
            // Сообщение прилетит обратно через chat:message broadcast — не дублируем локально
            setText('');
            return;
        }

        // === Путь 2: REST-fallback ===
        setSubmitting(true);
        try {
            const res = await Kubikon3DApi.postChatMessage(projectId, {
                user_id: userId,
                username: userInfo?.username || '',
                text: t,
            });
            const m = res.data?.message;
            if (m) {
                setMessages(prev => prev.some(x => x.id === m.id) ? prev : [...prev, m]);
                lastIdRef.current = Math.max(lastIdRef.current, m.id);
            }
            setText('');
        } catch (e) {
            const code = e?.response?.data?.error;
            const data = e?.response?.data || {};
            if (code === 'muted' || code === 'flood_muted') {
                setMuteInfo({
                    banned_until: data.banned_until,
                    last_reason: data.reason,
                    is_manual: data.is_manual,
                });
                setError(data.message || formatMuteMessage(data));
            } else if (code === 'too_frequent') {
                setError(data.message || 'Слишком быстро.');
            } else if (code === 'login_required') {
                onRequestAuth?.('писать в чат');
            } else if (code === 'invalid_text') {
                setError('Сообщение пустое.');
            } else {
                setError(data.message || code || 'Ошибка отправки');
            }
        }
        setSubmitting(false);
    };

    const onKeyDown = (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            send();
        }
    };

    // Compact mode — плавающее окно 320×380 в левом верхнем углу под top-bar.
    // Mobile mode — окно 280×320 в правом верхнем углу. Высота достаточная,
    // чтобы кнопка отправки и поле ввода поместились над клавиатурой.
    const wrapperStyle = compact
        ? (mobileMode ? {
            position: 'fixed', top: 8, right: 8,
            width: 280, height: 320, maxWidth: '90vw', maxHeight: '70vh',
            background: CHAT.bgPanel,
            border: `1px solid ${CHAT.border}`,
            borderRadius: 14,
            zIndex: 1100,
            display: 'flex', flexDirection: 'column',
            color: CHAT.text,
            fontFamily: CHAT.font,
            boxShadow: '0 8px 24px rgba(0,0,0,0.45)',
            backdropFilter: 'blur(20px)',
            WebkitBackdropFilter: 'blur(20px)',
            overflow: 'hidden',
            fontSize: 12,
            animation: 'chatSlideIn 280ms cubic-bezier(0.34, 1.56, 0.64, 1)',
        } : {
            position: 'fixed', top: 146, left: 14,
            width: 340, height: 380, maxWidth: '95vw',
            background: CHAT.bgPanel,
            border: `1px solid ${CHAT.border}`,
            borderRadius: 16,
            zIndex: 1100,
            display: 'flex', flexDirection: 'column',
            color: CHAT.text,
            fontFamily: CHAT.font,
            boxShadow: '0 16px 40px rgba(0,0,0,0.55), 0 0 0 1px rgba(51,87,255,0.12)',
            backdropFilter: 'blur(24px)',
            WebkitBackdropFilter: 'blur(24px)',
            overflow: 'hidden',
            animation: 'chatSlideIn 280ms cubic-bezier(0.34, 1.56, 0.64, 1)',
        })
        : {
            position: 'fixed',
            top: 0, left: 0, bottom: 0,
            width: 380, maxWidth: '95vw',
            background: CHAT.bgPanel,
            borderRight: `1px solid ${CHAT.border}`,
            zIndex: 1600,
            display: 'flex', flexDirection: 'column',
            color: CHAT.text,
            fontFamily: CHAT.font,
            boxShadow: '8px 0 32px rgba(0,0,0,0.55)',
            backdropFilter: 'blur(24px)',
            WebkitBackdropFilter: 'blur(24px)',
            overflow: 'hidden',
        };

    const transportInfo = transport === 'ws'
        ? { color: CHAT.success, label: 'Live', icon: '●' }
        : transport === 'polling'
            ? { color: CHAT.warning, label: 'Sync', icon: '●' }
            : { color: CHAT.textDim, label: '...', icon: '○' };

    return (
        <div style={wrapperStyle}>
            <style>{CHAT_KEYFRAMES}</style>

            {/* === Header с градиентной плашкой === */}
            <div style={{
                padding: '14px 16px',
                borderBottom: `1px solid ${CHAT.border}`,
                display: 'flex', alignItems: 'center', gap: 10,
                background: 'linear-gradient(180deg, rgba(51,87,255,0.16) 0%, rgba(51,87,255,0.03) 100%)',
                position: 'relative',
            }}>
                {/* Тонкая градиентная линия снизу */}
                <div style={{
                    position: 'absolute', left: 0, right: 0, bottom: -1, height: 1,
                    background: `linear-gradient(90deg, transparent, ${CHAT.accent}, transparent)`,
                    opacity: 0.6,
                }} />

                <div style={{
                    width: 32, height: 32, borderRadius: 10,
                    background: CHAT.gradientBrand,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontSize: 16,
                    boxShadow: '0 4px 12px rgba(51,87,255,0.45)',
                }}>💬</div>

                <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{
                        fontSize: 14, fontWeight: 800, color: CHAT.text,
                        letterSpacing: -0.2,
                    }}>Чат</div>
                    <div style={{
                        fontSize: 10, color: CHAT.textMuted, fontWeight: 700,
                        textTransform: 'uppercase', letterSpacing: 0.8,
                        display: 'inline-flex', alignItems: 'center', gap: 4,
                    }}>
                        <span style={{
                            color: transportInfo.color,
                            animation: transport === 'ws' ? 'chatPulse 2s ease-in-out infinite' : 'none',
                        }}>{transportInfo.icon}</span>
                        {transportInfo.label}
                    </div>
                </div>

                {/* Online-pill */}
                <div style={{
                    display: 'inline-flex', alignItems: 'center', gap: 6,
                    background: CHAT.successBg,
                    border: `1px solid ${CHAT.success}33`,
                    padding: '4px 10px',
                    borderRadius: 999,
                    fontSize: 11, fontWeight: 800,
                    color: CHAT.success,
                }}>
                    <span style={{
                        width: 6, height: 6, borderRadius: '50%',
                        background: CHAT.success,
                        animation: 'chatPulse 2s ease-in-out infinite',
                    }} />
                    {online}
                </div>

                <button
                    onClick={onClose}
                    style={iconBtn}
                    onMouseEnter={(e) => {
                        e.currentTarget.style.background = 'rgba(255,255,255,0.12)';
                        e.currentTarget.style.borderColor = CHAT.borderHover;
                    }}
                    onMouseLeave={(e) => {
                        e.currentTarget.style.background = 'rgba(255,255,255,0.04)';
                        e.currentTarget.style.borderColor = CHAT.border;
                    }}
                >✕</button>
            </div>

            {/* === Список сообщений === */}
            <div ref={listRef} style={{
                flex: 1, overflowY: 'auto',
                padding: '12px 14px',
                display: 'flex', flexDirection: 'column', gap: 6,
                scrollBehavior: 'smooth',
            }}>
                {!loaded ? (
                    <div style={{
                        margin: 'auto', textAlign: 'center', color: CHAT.textMuted,
                        display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
                    }}>
                        <div style={{
                            width: 22, height: 22,
                            border: `3px solid ${CHAT.accentBg}`,
                            borderTopColor: CHAT.accent,
                            borderRadius: '50%',
                            animation: 'chatSpin 0.8s linear infinite',
                        }} />
                        <div style={{ fontSize: 12, fontWeight: 600 }}>Подключение…</div>
                    </div>
                ) : messages.filter(m => !m.is_deleted).length === 0 ? (
                    <div style={{
                        margin: 'auto', padding: '24px 18px',
                        textAlign: 'center', color: CHAT.textMuted,
                        background: 'rgba(51,87,255,0.06)',
                        borderRadius: 14,
                        border: `1px dashed ${CHAT.border}`,
                        maxWidth: 240,
                    }}>
                        <div style={{
                            fontSize: 32, marginBottom: 8,
                            animation: 'chatFloat 3s ease-in-out infinite',
                        }}>💭</div>
                        <div style={{ fontSize: 13, fontWeight: 700, color: CHAT.text, marginBottom: 4 }}>
                            В чате пока тихо
                        </div>
                        <div style={{ fontSize: 11 }}>Напиши первым!</div>
                    </div>
                ) : (
                    messages.filter(m => !m.is_deleted).map((m, i) => (
                        <ChatMessage key={m.id} m={m} myUserId={userId} />
                    ))
                )}
            </div>

            {/* === Footer с инпутом === */}
            <div style={{
                borderTop: `1px solid ${CHAT.border}`,
                padding: 12,
                background: 'rgba(15,19,38,0.6)',
                flexShrink: 0,
            }}>
                {muteInfo && (
                    <MuteBanner muteInfo={muteInfo} onExpire={() => setMuteInfo(null)} />
                )}
                {error && !muteInfo && (
                    <div style={{
                        background: CHAT.dangerBg,
                        border: `1px solid ${CHAT.danger}55`,
                        borderRadius: 10,
                        padding: '8px 12px',
                        marginBottom: 10,
                        fontSize: 12, color: CHAT.danger, fontWeight: 600,
                        animation: 'chatFadeIn 220ms ease',
                    }}>
                        ⚠️ {error}
                    </div>
                )}
                {!userId ? (
                    <div style={{
                        padding: '12px 14px', textAlign: 'center',
                        background: CHAT.accentBg,
                        border: `1px solid ${CHAT.accent}55`,
                        borderRadius: 12, fontSize: 12, color: CHAT.text, fontWeight: 600,
                    }}>
                        🔒 Войди, чтобы общаться в чате
                    </div>
                ) : (
                    <ChatInput
                        text={text}
                        onChange={(v) => setText(v.slice(0, 300))}
                        onSend={send}
                        onKeyDown={onKeyDown}
                        disabled={submitting || !!muteInfo}
                        muteInfo={muteInfo}
                    />
                )}
            </div>
            <EmailConfirmNotice
                open={emailNotice}
                onClose={() => setEmailNotice(false)}
                action="писать в чате"
            />
        </div>
    );
};

// === Стили / палитра / keyframes ===
const CHAT = {
    bgPanel:    'rgba(20, 24, 45, 0.92)',
    bgInput:    'rgba(15, 19, 38, 0.85)',
    bgBubble:   'rgba(255, 255, 255, 0.05)',
    bgBubbleMine: 'linear-gradient(135deg, rgba(51,87,255,0.32) 0%, rgba(30,45,165,0.28) 100%)',
    border:     'rgba(255, 255, 255, 0.10)',
    borderHover:'rgba(255, 255, 255, 0.18)',
    text:       '#f1f5fb',
    textMuted:  'rgba(241, 245, 251, 0.62)',
    textDim:    'rgba(241, 245, 251, 0.42)',
    accent:     '#3357ff',
    accentBg:   'rgba(51, 87, 255, 0.18)',
    accentHover:'rgba(51, 87, 255, 0.28)',
    success:    '#22d97a',
    successBg:  'rgba(34, 217, 122, 0.18)',
    warning:    '#ffc857',
    danger:     '#ff6f7a',
    dangerBg:   'rgba(255, 111, 122, 0.16)',
    gradientBrand: 'linear-gradient(135deg, #3357ff 0%, #1e2da5 100%)',
    font:       '"Roboto Condensed", system-ui, -apple-system, sans-serif',
};

const CHAT_KEYFRAMES = `
@keyframes chatFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@keyframes chatSlideIn { from { opacity: 0; transform: translateX(-12px) scale(0.96); } to { opacity: 1; transform: translateX(0) scale(1); } }
@keyframes chatPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes chatSpin { to { transform: rotate(360deg); } }
@keyframes chatFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
`;

/** Цвет аватарки/ника — детерминирован по user_id (HSL). */
function colorForUser(uid) {
    if (uid == null) return CHAT.accent;
    const h = (uid * 137) % 360;
    return `hsl(${h}, 70%, 62%)`;
}

const ChatInput = ({ text, onChange, onSend, onKeyDown, disabled, muteInfo }) => {
    const [focus, setFocus] = useState(false);
    const [hovered, setHovered] = useState(false);
    const canSend = !disabled && text.trim();
    return (
        <div style={{
            display: 'flex', gap: 8, alignItems: 'stretch',
        }}>
            <input
                type="text"
                value={text}
                onChange={(e) => onChange(e.target.value)}
                onKeyDown={onKeyDown}
                onFocus={() => setFocus(true)}
                onBlur={() => setFocus(false)}
                placeholder={muteInfo ? '🔇 Чат заблокирован' : 'Сообщение… (Enter)'}
                disabled={disabled}
                maxLength={300}
                style={{
                    flex: 1,
                    background: CHAT.bgInput,
                    border: `1.5px solid ${focus ? CHAT.accent : CHAT.border}`,
                    borderRadius: 12,
                    padding: '10px 14px',
                    color: CHAT.text,
                    fontSize: 13, fontWeight: 500, fontFamily: CHAT.font,
                    outline: 'none',
                    opacity: muteInfo ? 0.5 : 1,
                    transition: 'all 150ms ease',
                    boxShadow: focus ? `0 0 0 3px ${CHAT.accentBg}` : 'none',
                }}
            />
            <button
                onClick={onSend}
                disabled={!canSend}
                onMouseEnter={() => setHovered(true)}
                onMouseLeave={() => setHovered(false)}
                style={{
                    padding: '0 14px', minWidth: 44,
                    background: canSend
                        ? CHAT.gradientBrand
                        : 'rgba(255,255,255,0.06)',
                    color: canSend ? '#fff' : CHAT.textDim,
                    border: `1px solid ${canSend ? 'transparent' : CHAT.border}`,
                    borderRadius: 12,
                    fontSize: 16, fontWeight: 800,
                    cursor: canSend ? 'pointer' : 'not-allowed',
                    fontFamily: CHAT.font,
                    transition: 'all 200ms ease',
                    boxShadow: canSend
                        ? (hovered
                            ? '0 8px 20px rgba(51,87,255,0.55)'
                            : '0 4px 12px rgba(51,87,255,0.35)')
                        : 'none',
                    transform: hovered && canSend ? 'translateY(-1px)' : 'none',
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}
                title="Отправить"
            >
                ➤
            </button>
        </div>
    );
};

const ChatMessage = ({ m, myUserId }) => {
    const isMine = myUserId === m.user_id;
    const userColor = colorForUser(m.user_id);
    const initial = (m.username || '?').slice(0, 1).toUpperCase();

    return (
        <div style={{
            display: 'flex', gap: 8, alignItems: 'flex-start',
            flexDirection: isMine ? 'row-reverse' : 'row',
            animation: 'chatFadeIn 220ms ease',
        }}>
            {/* Аватар-кружок с инициалом */}
            <div style={{
                width: 28, height: 28, flexShrink: 0,
                borderRadius: '50%',
                background: isMine ? CHAT.gradientBrand : userColor,
                color: '#fff',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontSize: 12, fontWeight: 800,
                boxShadow: isMine
                    ? '0 4px 10px rgba(51,87,255,0.40)'
                    : '0 2px 6px rgba(0,0,0,0.35)',
                marginTop: 2,
            }}>
                {initial}
            </div>

            {/* Пузырь сообщения */}
            <div style={{
                background: isMine ? CHAT.bgBubbleMine : CHAT.bgBubble,
                border: `1px solid ${isMine ? 'rgba(51,87,255,0.35)' : CHAT.border}`,
                borderRadius: 14,
                borderTopRightRadius: isMine ? 4 : 14,
                borderTopLeftRadius: isMine ? 14 : 4,
                padding: '6px 10px 8px',
                maxWidth: '78%',
                minWidth: 0,
            }}>
                <div style={{
                    display: 'flex', alignItems: 'baseline', gap: 6,
                    flexDirection: isMine ? 'row-reverse' : 'row',
                }}>
                    <a
                        href={`https://rublox.pro/app/profile/${m.user_id}`}
                        style={{
                            fontSize: 11, fontWeight: 800, textDecoration: 'none',
                            color: isMine ? '#fff' : userColor,
                            letterSpacing: 0.1,
                        }}
                    >
                        {isMine ? 'Ты' : (m.username || `#${m.user_id}`)}
                    </a>
                    <span style={{
                        fontSize: 9, color: CHAT.textDim, fontWeight: 600,
                    }}>
                        {formatTimeShort(m.created_at)}
                    </span>
                </div>
                <div style={{
                    fontSize: 13, color: CHAT.text,
                    whiteSpace: 'pre-wrap', wordBreak: 'break-word',
                    marginTop: 2, lineHeight: 1.4,
                }}>
                    {m.text}
                </div>
            </div>
        </div>
    );
};

const MuteBanner = ({ muteInfo, onExpire }) => {
    const [now, setNow] = useState(Date.now());
    useEffect(() => {
        const t = setInterval(() => setNow(Date.now()), 1000);
        return () => clearInterval(t);
    }, []);
    if (!muteInfo?.banned_until) return null;
    const untilMs = new Date(muteInfo.banned_until.replace(' ', 'T')).getTime();
    const remaining = untilMs - now;
    if (remaining <= 0) {
        setTimeout(onExpire, 0);
        return null;
    }
    const fmt = formatRemaining(remaining);
    return (
        <div style={{
            background: CHAT.dangerBg,
            border: `1px solid ${CHAT.danger}55`,
            borderRadius: 12,
            padding: '10px 12px',
            marginBottom: 10,
            fontSize: 12, color: CHAT.danger,
            display: 'flex', alignItems: 'center', gap: 10,
        }}>
            <span style={{ fontSize: 18 }}>🔇</span>
            <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 800 }}>
                    Мьют чата · <span style={{ fontVariantNumeric: 'tabular-nums' }}>{fmt}</span>
                </div>
                {muteInfo.last_reason && (
                    <div style={{
                        fontSize: 11, color: CHAT.danger, marginTop: 2, opacity: 0.85,
                    }}>
                        Причина: {translateReason(muteInfo.last_reason)}
                    </div>
                )}
            </div>
        </div>
    );
};

function formatRemaining(ms) {
    const s = Math.ceil(ms / 1000);
    if (s < 60) return `${s}с`;
    const m = Math.floor(s / 60);
    if (m < 60) return `${m}м ${s % 60}с`;
    const h = Math.floor(m / 60);
    return `${h}ч ${m % 60}м`;
}

function formatMuteMessage(data) {
    const r = translateReason(data.reason);
    if (data.banned_until) return `🔇 Чат заблокирован до ${data.banned_until} (${r})`;
    return `🔇 ${r}`;
}

function translateReason(r) {
    if (r === 'profanity') return 'мат';
    if (r === 'links') return 'ссылки/спам';
    if (r === 'flood') return 'флуд';
    if (r === 'caps') return 'CAPS';
    if (r === 'manual') return 'вручную модератором';
    return r || 'нарушение правил';
}

const iconBtn = {
    background: 'rgba(255,255,255,0.04)',
    border: `1px solid ${CHAT.border}`,
    borderRadius: 8,
    color: CHAT.text,
    width: 28, height: 28,
    cursor: 'pointer',
    fontSize: 13, fontWeight: 700,
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    fontFamily: CHAT.font,
    transition: 'all 150ms ease',
};

export default KubikonChatPanel;
