<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Децентрализованный P2P Чат</title>
    <style>
        /* Основные стили */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #c3ec52, #0ba29d);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .chat-container {
            background-color: #ffffff;
            width: 100%;
            max-width: 900px;
            height: 90vh;
            border-radius: 12px;
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        header {
            background-color: #4CAF50;
            color: white;
            padding: 20px;
            text-align: center;
            position: relative;
        }

        header h1 {
            font-size: 1.8rem;
        }

        .peer-id {
            font-size: 0.9rem;
            margin-top: 5px;
            opacity: 0.8;
            word-wrap: break-word;
        }

        .main {
            flex: 1;
            display: flex;
            overflow: hidden;
        }

        .sidebar {
            width: 250px;
            background-color: #f4f4f4;
            border-right: 1px solid #ddd;
            padding: 20px;
            display: flex;
            flex-direction: column;
        }

        .sidebar-section {
            margin-bottom: 30px;
        }

        .sidebar label {
            display: block;
            margin-bottom: 8px;
            font-weight: bold;
            color: #333;
        }

        .sidebar input[type="text"] {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 6px;
            margin-bottom: 10px;
            transition: border-color 0.3s;
        }

        .sidebar input[type="text"]:focus {
            border-color: #4CAF50;
            outline: none;
        }

        .sidebar button {
            width: 100%;
            padding: 10px;
            background-color: #4CAF50;
            border: none;
            border-radius: 6px;
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .sidebar button:hover {
            background-color: #45a049;
        }

        .online-section h3 {
            margin-bottom: 10px;
            color: #333;
        }

        #online-users {
            list-style: none;
            max-height: 300px;
            overflow-y: auto;
        }

        #online-users li {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 10px;
            border-bottom: 1px solid #ddd;
            border-radius: 6px;
            margin-bottom: 5px;
            background-color: #fff;
            transition: background-color 0.3s;
            cursor: pointer; /* Сделать пункт списка кликабельным */
        }

        #online-users li:hover {
            background-color: #f1f1f1;
        }

        #online-users li.active {
            background-color: #d1e7dd; /* Цвет для активного пользователя */
        }

        .user-info {
            display: flex;
            align-items: center;
            flex: 1;
        }

        .user-info .status {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: #4CAF50;
            margin-right: 10px;
        }

        .user-info .user-id {
            font-size: 0.9rem;
            color: #333;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            max-width: 140px;
        }

        .user-actions {
            display: flex;
            gap: 5px;
        }

        .user-actions button {
            padding: 5px 10px;
            background-color: #2196F3;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            font-size: 0.8rem;
            transition: background-color 0.3s;
        }

        .user-actions button:hover {
            background-color: #1976D2;
        }

        .chat-section {
            flex: 1;
            display: flex;
            flex-direction: column;
            padding: 20px;
            background-color: #fafafa;
            position: relative;
        }

        #active-peer {
            margin-bottom: 10px;
            font-weight: bold;
            color: #333;
        }

        #messages {
            flex: 1;
            overflow-y: auto;
            padding-right: 10px;
            margin-bottom: 10px;
        }

        .message {
            margin-bottom: 15px;
            max-width: 70%;
            padding: 10px 15px;
            border-radius: 20px;
            position: relative;
            word-wrap: break-word;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }

        .message.self {
            background-color: #DCF8C6;
            align-self: flex-end;
            border-bottom-right-radius: 0;
        }

        .message.other {
            background-color: #FFFFFF;
            border: 1px solid #ddd;
            align-self: flex-start;
            border-bottom-left-radius: 0;
        }

        .message.system {
            background-color: #e0e0e0;
            text-align: center;
            max-width: 100%;
            margin: 10px auto;
            border-radius: 10px;
            padding: 8px 12px;
            font-style: italic;
            color: #555;
        }

        .input-section, .file-section {
            display: flex;
            align-items: center;
            margin-top: 10px;
        }

        .input-section input[type="text"],
        .file-section input[type="file"] {
            flex: 1;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 6px;
            margin-right: 10px;
            transition: border-color 0.3s;
        }

        .input-section input[type="text"]:focus,
        .file-section input[type="file"]:focus {
            border-color: #4CAF50;
            outline: none;
        }

        .input-section button,
        .file-section button {
            padding: 10px 15px;
            background-color: #4CAF50;
            border: none;
            border-radius: 6px;
            color: white;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .input-section button:hover,
        .file-section button:hover {
            background-color: #45a049;
        }

        #call-btn, #video-call-btn, #share-screen-btn {
            margin-top: 15px;
            background-color: #2196F3;
            color: white;
            width: 100%;
            padding: 10px;
            border: none;
            border-radius: 6px;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        #video-call-btn {
            background-color: #FF9800;
            margin-top: 10px;
        }

        #share-screen-btn {
            background-color: #9C27B0;
            margin-top: 10px;
        }

        #call-btn:hover, #video-call-btn:hover, #share-screen-btn:hover {
            opacity: 0.9;
        }

        /* Окно звонка */
        .call-window {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #ffffff;
            padding: 30px;
            border: 2px solid #4CAF50;
            border-radius: 12px;
            box-shadow: 0 8px 16px rgba(0,0,0,0.3);
            display: none;
            z-index: 1000;
            width: 350px;
            text-align: center;
        }

        .call-window.active {
            display: block;
        }

        .call-window p {
            margin-bottom: 20px;
            font-size: 1rem;
            color: #333;
        }

        .call-window .accept-buttons {
            display: flex;
            flex-direction: column;
            gap: 10px;
            margin-bottom: 20px;
        }

        .call-window .accept-buttons button {
            width: 100%;
            padding: 10px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-weight: bold;
            transition: background-color 0.3s;
        }

        .call-window .accept-buttons button.btn-audio {
            background-color: #4CAF50;
            color: white;
        }

        .call-window .accept-buttons button.btn-audio:hover {
            background-color: #45a049;
        }

        .call-window .accept-buttons button.btn-video {
            background-color: #FF9800;
            color: white;
        }

        .call-window .accept-buttons button.btn-video:hover {
            background-color: #F57C00;
        }

        .call-window .accept-buttons button.btn-screen {
            background-color: #9C27B0;
            color: white;
        }

        .call-window .accept-buttons button.btn-screen:hover {
            background-color: #7B1FA2;
        }

        .call-window button.reject {
            padding: 10px 20px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-weight: bold;
            background-color: #f44336;
            color: white;
            transition: background-color 0.3s;
        }

        .call-window button.reject:hover {
            background-color: #d32f2f;
        }

        /* Аудио и Видео элементы */
        .media-chat {
            margin-top: 10px;
            max-width: 100%;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .media-chat audio,
        .media-chat video {
            width: 100%;
            max-height: 300px;
            margin-top: 5px;
            border: 1px solid #ddd;
            border-radius: 6px;
        }

        /* Медиа запросы для адаптивности */
        @media (max-width: 768px) {
            .main {
                flex-direction: column;
            }

            .sidebar {
                width: 100%;
                border-right: none;
                border-bottom: 1px solid #ddd;
            }

            .chat-section {
                padding: 15px;
            }

            .input-section, .file-section {
                flex-direction: column;
            }

            .input-section input[type="text"],
            .file-section input[type="file"] {
                margin-right: 0;
                margin-bottom: 10px;
                width: 100%;
            }

            .input-section button,
            .file-section button,
            #call-btn,
            #video-call-btn,
            #share-screen-btn {
                width: 100%;
            }
        }
    </style>
</head>
<body>
    <div class="chat-container">
        <header>
            <h1>Децентрализованный P2P Чат</h1>
            <p class="peer-id">Ваш Peer ID: <span id="peer-id">Подключение...</span></p>
        </header>
        <div class="main">
            <div class="sidebar">
                <div class="sidebar-section connect-section">
                    <label for="remote-id">Подключиться к Peer ID:</label>
                    <input type="text" id="remote-id" placeholder="Введите Peer ID другого пользователя">
                    <button id="connect-btn">Подключиться</button>
                </div>
                <div class="sidebar-section online-section">
                    <h3>Онлайн пользователи:</h3>
                    <ul id="online-users">
                        <!-- Список онлайн пользователей -->
                    </ul>
                </div>
            </div>
            <div class="chat-section">
                <div id="active-peer">Нет активного чата</div>
                <div id="messages"></div>
                <div class="input-section">
                    <input type="text" id="message-input" placeholder="Введите сообщение">
                    <button id="send-btn">Отправить</button>
                </div>
                <div class="file-section">
                    <input type="file" id="file-input">
                    <button id="send-file-btn">Отправить файл</button>
                </div>
                <!-- Новые кнопки для видео-звонка и демонстрации экрана -->
                <button id="call-btn">Позвонить</button>
                <button id="video-call-btn">Видео звонок</button>
                <button id="share-screen-btn">Демонстрация экрана</button>
            </div>
        </div>
    </div>

    <!-- Окно звонка -->
    <div class="call-window" id="call-window">
        <p id="call-status">Входящий звонок от <span id="caller-id"></span></p>
        <div class="accept-buttons">
            <button class="btn-audio">Принять аудио звонок</button>
            <button class="btn-video">Принять видео звонок</button>
            <button class="btn-screen">Принять демонстрацию экрана</button>
        </div>
        <button class="reject">Отклонить</button>
    </div>

    <!-- Подключение PeerJS через CDN -->
    <script src="https://unpkg.com/peerjs@1.4.7/dist/peerjs.min.js"></script>
    <script>
        class P2PChat {
            constructor() {
                this.peer = null;
                this.connections = new Map();
                this.currentCall = null;
                this.localStream = null;
                this.activePeerId = null; // Активный Peer ID для чата

                // Элементы интерфейса
                this.peerIdDisplay = document.getElementById('peer-id');
                this.connectBtn = document.getElementById('connect-btn');
                this.remoteIdInput = document.getElementById('remote-id');
                this.messagesArea = document.getElementById('messages');
                this.sendBtn = document.getElementById('send-btn');
                this.messageInput = document.getElementById('message-input');
                this.onlineUsersList = document.getElementById('online-users');
                this.fileInput = document.getElementById('file-input');
                this.sendFileBtn = document.getElementById('send-file-btn');
                this.callBtn = document.getElementById('call-btn');
                this.videoCallBtn = document.getElementById('video-call-btn'); // Новая кнопка
                this.shareScreenBtn = document.getElementById('share-screen-btn'); // Новая кнопка
                this.activePeerDisplay = document.getElementById('active-peer');

                // Элементы окна звонка
                this.callWindow = document.getElementById('call-window');
                this.callerIdSpan = document.getElementById('caller-id');
                this.acceptAudioBtn = this.callWindow.querySelector('.btn-audio');
                this.acceptVideoBtn = this.callWindow.querySelector('.btn-video');
                this.acceptScreenBtn = this.callWindow.querySelector('.btn-screen');
                this.rejectCallBtn = this.callWindow.querySelector('.reject');

                this.currentIncomingCall = null; // Ссылка на текущий входящий звонок

                this.initPeer();
                this.bindEvents();
            }

            initPeer() {
                // Инициализация PeerJS с генерацией уникального ID
                this.peer = new Peer();

                this.peer.on('open', (id) => {
                    this.peerIdDisplay.textContent = id;
                    this.addOnlineUser(id, true); // Добавить себя в список онлайн пользователей
                });

                this.peer.on('connection', (conn) => this.handleConnection(conn));

                this.peer.on('call', (call) => this.handleIncomingCall(call));

                this.peer.on('error', (err) => {
                    console.error(err);
                    alert('Произошла ошибка: ' + err);
                });
            }

            bindEvents() {
                this.connectBtn.addEventListener('click', () => this.connectToPeer());
                this.sendBtn.addEventListener('click', () => this.sendMessage());
                this.messageInput.addEventListener('keypress', (e) => {
                    if (e.key === 'Enter') this.sendMessage();
                });
                this.sendFileBtn.addEventListener('click', () => this.sendFile());
                this.callBtn.addEventListener('click', () => this.initiateCallButtonHandler());
                this.videoCallBtn.addEventListener('click', () => this.initiateVideoCall()); // Обработчик видео-звонка
                this.shareScreenBtn.addEventListener('click', () => this.initiateScreenShare()); // Обработчик демонстрации экрана

                // Обработчики для окна звонка
                this.acceptAudioBtn.addEventListener('click', () => this.acceptCall('audio'));
                this.acceptVideoBtn.addEventListener('click', () => this.acceptCall('video'));
                this.acceptScreenBtn.addEventListener('click', () => this.acceptCall('screen'));
                this.rejectCallBtn.addEventListener('click', () => this.rejectCall());

                // Обработчик клика по пользователю для выбора активного чата
                this.onlineUsersList.addEventListener('click', (e) => {
                    const li = e.target.closest('li');
                    if (li && !li.classList.contains('active')) {
                        this.selectActivePeer(li);
                    }
                });
            }

            connectToPeer() {
                const remoteId = this.remoteIdInput.value.trim();
                if (!remoteId) {
                    alert('Введите Peer ID для подключения.');
                    return;
                }

                if (this.connections.has(remoteId)) {
                    alert('Уже подключены к этому Peer.');
                    return;
                }

                const conn = this.peer.connect(remoteId);

                conn.on('open', () => {
                    this.setupConnection(conn);
                    this.addOnlineUser(remoteId);
                    this.appendSystemMessage(`Соединение с ${remoteId} установлено.`);
                    if (!this.activePeerId) {
                        this.setActivePeer(remoteId);
                    }
                });

                conn.on('error', (err) => {
                    console.error(`Ошибка соединения с ${remoteId}:`, err);
                    this.appendSystemMessage(`Ошибка соединения с ${remoteId}: ${err}`);
                });

                conn.on('close', () => {
                    this.appendSystemMessage(`Соединение с ${remoteId} закрыто.`);
                    this.removeOnlineUser(remoteId);
                    this.connections.delete(remoteId);
                    if (this.activePeerId === remoteId) {
                        this.activePeerId = null;
                        this.activePeerDisplay.textContent = 'Нет активного чата';
                    }
                });
            }

            handleConnection(conn) {
                if (this.connections.has(conn.peer)) {
                    console.warn(`Уже есть соединение с ${conn.peer}`);
                    conn.close();
                    return;
                }

                this.setupConnection(conn);
                this.addOnlineUser(conn.peer);
                this.appendSystemMessage(`Peer ${conn.peer} подключился.`);
                if (!this.activePeerId) {
                    this.setActivePeer(conn.peer);
                }
            }

            setupConnection(conn) {
                this.connections.set(conn.peer, conn);

                conn.on('data', (data) => this.handleIncomingData(data, conn.peer));

                conn.on('close', () => {
                    this.appendSystemMessage(`Соединение с ${conn.peer} закрыто.`);
                    this.removeOnlineUser(conn.peer);
                    this.connections.delete(conn.peer);
                    if (this.activePeerId === conn.peer) {
                        this.activePeerId = null;
                        this.activePeerDisplay.textContent = 'Нет активного чата';
                    }
                });
            }

            handleIncomingData(data, peerId) {
                try {
                    const parsedData = JSON.parse(data);
                    switch (parsedData.type) {
                        case 'message':
                            this.displayMessage(parsedData.content, 'other');
                            break;
                        case 'file':
                            this.receiveFile(parsedData, peerId);
                            break;
                        default:
                            console.warn('Неизвестный тип сообщения:', parsedData.type);
                    }
                } catch (error) {
                    console.error('Ошибка разбора данных:', error);
                    this.appendSystemMessage(`Получены некорректные данные от ${peerId}.`);
                }
            }

            sendMessage() {
                const message = this.messageInput.value.trim();
                if (!message) return;

                if (!this.activePeerId) {
                    alert('Выберите пользователя для отправки сообщения.');
                    return;
                }

                const conn = this.connections.get(this.activePeerId);
                if (!conn || conn.open === false) {
                    alert('Нет открытого соединения для отправки сообщения.');
                    return;
                }

                const data = JSON.stringify({ type: 'message', content: message });

                try {
                    conn.send(data);
                    this.displayMessage(message, 'self');
                    this.messageInput.value = '';
                } catch (err) {
                    console.error('Ошибка отправки сообщения:', err);
                    this.appendSystemMessage(`Не удалось отправить сообщение пользователю ${this.activePeerId}.`);
                }
            }

            displayMessage(message, type) {
                const messageDiv = document.createElement('div');
                messageDiv.classList.add('message', type);
                messageDiv.textContent = message;

                this.messagesArea.appendChild(messageDiv);
                this.scrollToBottom();
            }

            appendSystemMessage(message) {
                const messageDiv = document.createElement('div');
                messageDiv.classList.add('message', 'system');
                messageDiv.textContent = message;

                this.messagesArea.appendChild(messageDiv);
                this.scrollToBottom();
            }

            addOnlineUser(userId, isSelf = false) {
                if ([...this.onlineUsersList.children].some(li => li.querySelector('.user-id').textContent === userId)) {
                    return;
                }

                const li = document.createElement('li');

                const userInfo = document.createElement('div');
                userInfo.classList.add('user-info');

                const status = document.createElement('span');
                status.classList.add('status');
                status.style.backgroundColor = isSelf ? '#4CAF50' : '#4CAF50';

                const userIdSpan = document.createElement('span');
                userIdSpan.classList.add('user-id');
                userIdSpan.textContent = userId;

                userInfo.appendChild(status);
                userInfo.appendChild(userIdSpan);

                li.appendChild(userInfo);

                if (!isSelf) {
                    const userActions = document.createElement('div');
                    userActions.classList.add('user-actions');

                    const callButton = document.createElement('button');
                    callButton.textContent = 'Позвонить';
                    callButton.style.backgroundColor = '#2196F3';
                    callButton.onclick = (e) => {
                        e.stopPropagation(); // Предотвращает выбор пользователя при нажатии кнопки
                        this.startCall(userId);
                    };

                    const videoCallButton = document.createElement('button'); // Новая кнопка для видео-звонка
                    videoCallButton.textContent = 'Видео звонок';
                    videoCallButton.style.backgroundColor = '#FF9800';
                    videoCallButton.onclick = (e) => {
                        e.stopPropagation();
                        this.startVideoCall(userId);
                    };

                    const shareScreenButton = document.createElement('button'); // Новая кнопка для демонстрации экрана
                    shareScreenButton.textContent = 'Демонстрация экрана';
                    shareScreenButton.style.backgroundColor = '#9C27B0';
                    shareScreenButton.onclick = (e) => {
                        e.stopPropagation();
                        this.shareScreen(userId);
                    };

                    userActions.appendChild(callButton);
                    userActions.appendChild(videoCallButton);
                    userActions.appendChild(shareScreenButton);
                    li.appendChild(userActions);
                }

                this.onlineUsersList.appendChild(li);
                if (!isSelf) {
                    this.appendSystemMessage(`${userId} подключился.`);
                }
            }

            removeOnlineUser(userId) {
                [...this.onlineUsersList.children].forEach(li => {
                    if (li.querySelector('.user-id').textContent === userId) {
                        this.onlineUsersList.removeChild(li);
                        this.appendSystemMessage(`${userId} отключился.`);
                    }
                });
            }

            setActivePeer(peerId) {
                // Снять выделение с текущего активного пользователя
                [...this.onlineUsersList.children].forEach(li => {
                    if (li.classList.contains('active')) {
                        li.classList.remove('active');
                    }
                });

                // Выбрать нового активного пользователя
                const targetLi = [...this.onlineUsersList.children].find(li => li.querySelector('.user-id').textContent === peerId);
                if (targetLi) {
                    targetLi.classList.add('active');
                    this.activePeerId = peerId;
                    this.activePeerDisplay.textContent = `Активный чат с: ${peerId}`;
                    this.clearMessages();
                }
            }

            selectActivePeer(li) {
                const peerId = li.querySelector('.user-id').textContent;
                this.setActivePeer(peerId);
            }

            clearMessages() {
                this.messagesArea.innerHTML = '';
            }

            sendFile() {
                const file = this.fileInput.files[0];
                if (!file) {
                    alert('Пожалуйста, выберите файл для отправки.');
                    return;
                }

                if (!this.activePeerId) {
                    alert('Выберите пользователя для отправки файла.');
                    return;
                }

                const conn = this.connections.get(this.activePeerId);
                if (!conn || conn.open === false) {
                    alert('Нет открытого соединения для отправки файла.');
                    return;
                }

                const reader = new FileReader();
                reader.onload = () => {
                    const arrayBuffer = reader.result;
                    const uint8Array = Array.from(new Uint8Array(arrayBuffer));

                    const data = JSON.stringify({
                        type: 'file',
                        content: uint8Array,
                        fileName: file.name,
                        fileType: file.type
                    });

                    try {
                        conn.send(data);
                        this.appendSystemMessage(`Вы отправили файл: ${file.name} пользователю ${this.activePeerId}.`);
                        this.fileInput.value = '';
                    } catch (err) {
                        console.error('Ошибка отправки файла:', err);
                        this.appendSystemMessage(`Не удалось отправить файл пользователю ${this.activePeerId}.`);
                    }
                };

                reader.onerror = (error) => {
                    console.error('Ошибка чтения файла:', error);
                    alert('Не удалось прочитать файл.');
                };

                reader.readAsArrayBuffer(file);
            }

            receiveFile(data, peerId) {
                const { content, fileName, fileType } = data;

                if (!content || !fileName || !fileType) {
                    console.error('Получены неполные данные файла:', data);
                    this.appendSystemMessage(`Получены некорректные данные файла от ${peerId}.`);
                    return;
                }

                try {
                    const uint8Array = new Uint8Array(content);
                    const blob = new Blob([uint8Array], { type: fileType });

                    const link = document.createElement('a');
                    const url = URL.createObjectURL(blob);
                    link.href = url;
                    link.download = fileName;
                    link.textContent = `Скачать файл: ${fileName}`;
                    link.className = 'file-link';
                    link.style.color = '#0066cc';
                    link.style.textDecoration = 'none';
                    link.style.display = 'block';
                    link.style.marginTop = '5px';
                    link.target = '_blank';

                    const fileMessage = document.createElement('div');
                    fileMessage.classList.add('message', 'other');
                    fileMessage.innerHTML = `Друг отправил файл: ${fileName}`;
                    fileMessage.appendChild(link);

                    this.messagesArea.appendChild(fileMessage);
                    this.scrollToBottom();
                } catch (err) {
                    console.error('Ошибка обработки полученного файла:', err);
                    this.appendSystemMessage(`Не удалось обработать файл от ${peerId}.`);
                }
            }

            // Инициация аудио-звонка
            startCall(peerId) {
                navigator.mediaDevices.getUserMedia({ audio: true, video: false })
                    .then(stream => {
                        this.localStream = stream;
                        const call = this.peer.call(peerId, stream);
                        this.setupCall(call);
                        this.appendSystemMessage(`Вы позвонили ${peerId}.`);
                    })
                    .catch(err => {
                        console.error('Ошибка доступа к микрофону:', err);
                        alert('Не удалось получить доступ к микрофону.');
                    });
            }

            // Инициация видео-звонка
            startVideoCall(peerId) {
                navigator.mediaDevices.getUserMedia({ audio: true, video: true })
                    .then(stream => {
                        this.localStream = stream;
                        const call = this.peer.call(peerId, stream);
                        this.setupCall(call);
                        this.appendSystemMessage(`Вы начали видео-звонок с ${peerId}.`);
                    })
                    .catch(err => {
                        console.error('Ошибка доступа к камере/микрофону:', err);
                        alert('Не удалось получить доступ к камере или микрофону.');
                    });
            }

            // Инициация демонстрации экрана через кнопку
            initiateScreenShare() {
                const remoteId = this.activePeerId;
                if (!remoteId) {
                    alert('Выберите пользователя для демонстрации экрана.');
                    return;
                }

                if (remoteId === this.peer.id) {
                    alert('Вы не можете демонстрировать экран себе.');
                    return;
                }

                this.shareScreen(remoteId);
            }

            // Демонстрация экрана
            shareScreen(peerId) {
                navigator.mediaDevices.getDisplayMedia({ video: true, audio: false })
                    .then(stream => {
                        this.localStream = stream;
                        const call = this.peer.call(peerId, stream);
                        this.setupCall(call);
                        this.appendSystemMessage(`Вы начали демонстрацию экрана для ${peerId}.`);

                        // Отслеживание завершения демонстрации экрана
                        stream.getVideoTracks()[0].addEventListener('ended', () => {
                            if (this.currentCall) {
                                this.currentCall.close();
                                this.appendSystemMessage(`Демонстрация экрана для ${peerId} завершена.`);
                            }
                        });
                    })
                    .catch(err => {
                        console.error('Ошибка при захвате экрана:', err);
                        alert('Не удалось захватить экран.');
                    });
            }

            handleIncomingCall(call) {
                this.callWindow.classList.add('active');
                this.callerIdSpan.textContent = call.peer;
                this.currentIncomingCall = call; // Сохраняем текущий звонок для обработки
            }

            acceptCall(type) {
                if (!this.currentIncomingCall) {
                    alert('Нет текущего звонка.');
                    return;
                }

                let constraints;

                switch(type) {
                    case 'audio':
                        constraints = { audio: true, video: false };
                        break;
                    case 'video':
                        constraints = { audio: true, video: true };
                        break;
                    case 'screen':
                        constraints = { audio: false, video: true };
                        break;
                    default:
                        constraints = { audio: true, video: false };
                }

                // Для демонстрации экрана нужно использовать getDisplayMedia, но PeerJS call.answer принимает MediaStream,
                // поэтому при принятии демонстрации экрана нужно заранее получить его и использовать
                if (type === 'screen') {
                    navigator.mediaDevices.getDisplayMedia({ video: true, audio: false })
                        .then(stream => {
                            this.localStream = stream;
                            this.currentIncomingCall.answer(stream);
                            this.setupCall(this.currentIncomingCall);
                            this.callWindow.classList.remove('active');
                            this.appendSystemMessage(`Вы приняли демонстрацию экрана от ${this.currentIncomingCall.peer}.`);
                            this.currentIncomingCall = null;
                        })
                        .catch(err => {
                            console.error('Ошибка доступа к экрану:', err);
                            alert('Не удалось получить доступ к экрану.');
                            this.callWindow.classList.remove('active');
                            this.currentIncomingCall = null;
                        });
                } else {
                    navigator.mediaDevices.getUserMedia(constraints)
                        .then(stream => {
                            this.localStream = stream;
                            this.currentIncomingCall.answer(stream);
                            this.setupCall(this.currentIncomingCall);
                            this.callWindow.classList.remove('active');
                            this.appendSystemMessage(`Вы приняли ${type === 'audio' ? 'аудио' : 'видео'} звонок от ${this.currentIncomingCall.peer}.`);
                            this.currentIncomingCall = null;
                        })
                        .catch(err => {
                            console.error(`Ошибка доступа к ${type === 'audio' ? 'микрофону' : 'камере'}:`, err);
                            alert(`Не удалось получить доступ к ${type === 'audio' ? 'микрофону' : 'камере'}.`);
                            this.callWindow.classList.remove('active');
                            this.currentIncomingCall = null;
                        });
                }
            }

            rejectCall() {
                if (!this.currentIncomingCall) {
                    alert('Нет текущего звонка.');
                    return;
                }

                this.currentIncomingCall.close();
                this.callWindow.classList.remove('active');
                this.appendSystemMessage(`Вы отклонили звонок от ${this.currentIncomingCall.peer}.`);
                this.currentIncomingCall = null;
            }

            setupCall(call) {
                if (this.currentCall) {
                    this.currentCall.close();
                }
                this.currentCall = call;

                call.on('stream', (remoteStream) => {
                    // Проверяем, содержит ли поток видео или аудио
                    const hasVideo = remoteStream.getVideoTracks().length > 0;
                    const hasAudio = remoteStream.getAudioTracks().length > 0;

                    const mediaContainer = document.createElement('div');
                    mediaContainer.classList.add('media-chat');

                    if (hasVideo) {
                        const video = document.createElement('video');
                        video.srcObject = remoteStream;
                        video.autoplay = true;
                        video.controls = true;
                        mediaContainer.appendChild(video);
                    }

                    if (hasAudio) {
                        const audio = document.createElement('audio');
                        audio.srcObject = remoteStream;
                        audio.autoplay = true;
                        audio.controls = true;
                        mediaContainer.appendChild(audio);
                    }

                    this.messagesArea.appendChild(mediaContainer);
                    this.scrollToBottom();
                });

                call.on('close', () => {
                    this.appendSystemMessage('Звонок завершен.');
                    if (this.localStream) {
                        this.localStream.getTracks().forEach(track => track.stop());
                        this.localStream = null;
                    }
                    this.currentCall = null;
                });

                call.on('error', (err) => {
                    console.error('Ошибка звонка:', err);
                    this.appendSystemMessage('Произошла ошибка во время звонка.');
                });
            }

            initiateCallButtonHandler() {
                const remoteId = this.remoteIdInput.value.trim();

                if (!remoteId) {
                    alert('Введите Peer ID для звонка.');
                    return;
                }

                if (remoteId === this.peer.id) {
                    alert('Вы не можете звонить себе.');
                    return;
                }

                this.startCall(remoteId); // Вызываем метод startCall
            }

            initiateVideoCall() {
                const remoteId = this.remoteIdInput.value.trim() || this.activePeerId;
                if (!remoteId) {
                    alert('Выберите пользователя для видео-звонка.');
                    return;
                }

                if (remoteId === this.peer.id) {
                    alert('Вы не можете звонить себе.');
                    return;
                }

                this.startVideoCall(remoteId);
            }

            initiateScreenShare() {
                const remoteId = this.activePeerId;
                if (!remoteId) {
                    alert('Выберите пользователя для демонстрации экрана.');
                    return;
                }

                if (remoteId === this.peer.id) {
                    alert('Вы не можете демонстрировать экран себе.');
                    return;
                }

                this.shareScreen(remoteId);
            }

            scrollToBottom() {
                this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
            }
        }

        document.addEventListener('DOMContentLoaded', () => {
            new P2PChat();
        });
    </script>
</body>
</html>

ошибка 1 (4) — копия.html:233 Ошибка при инициализации бекенда: TypeError: tf.backendNames is not a function
    at initializeBackend (1 (4) — копия.html:222:35)
    at init (1 (4) — копия.html:439:13)
tfjs@latest:17 Orthogonal initializer is being called on a matrix with more than 2000 (262144) elements: Slowness may result.
tfjs@latest:17 Uncaught (in promise) Error: Argument 'x' passed to 'floor' must be float32 tensor, but got int32 tensor
    at M5 (tfjs@latest:17:236965)
    at L5 (tfjs@latest:17:237210)
    at floor_ (tfjs@latest:17:311010)
    at floor__op (tfjs@latest:17:239699)
    at tfjs@latest:17:569656
    at tfjs@latest:17:220203
    at e.value (tfjs@latest:17:220344)
    at e.value (tfjs@latest:17:220100)
    at X5 (tfjs@latest:17:243540)
    at lle (tfjs@latest:17:569632)
﻿