import React, { useState, useEffect, useRef } from 'react';
import { useNavigate, useParams, useLocation } from 'react-router-dom';
import vectorImage from './images/Vector.png';
import { io } from 'socket.io-client';
import './Tournament.css';

const server_url = process.env.REACT_APP_API_URL;

const Tournament = () => {
  const { code } = useParams();
  const navigate = useNavigate();
  const location = useLocation();
  const [previousScoreInput, setPreviousScoreInput] = useState(null);
  const { state } = location;

  const [activeCircle, setActiveCircle] = useState(null);
  const [playerScoreInput, setPlayerScoreInput] = useState(null);
  const [userData, setUserData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // Используем useRef для хранения очереди несообщенных действий
  const unsentActionsQueueRef = useRef([]);

  // Создаем реф для сокета
  const socketRef = useRef(null);

  useEffect(() => {
    // Создаем соединение с сокетом только один раз при монтировании компонента
    socketRef.current = io(`${server_url}`, {
      transports: ['websocket', 'polling'],
      secure: true,
    });

    socketRef.current.on('connect', () => {
      console.log('Connected to WebSocket server');
    });

    return () => {
      // Отключаем сокет при размонтировании компонента
      socketRef.current.disconnect();
    };
  }, []);

  useEffect(() => {
    const fetchUserData = async () => {
      try {
        const response = await fetch(`${server_url}/api/user/${code}`);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const data = await response.json();
        setUserData(data);
        if (
          state &&
          state.activeCircle &&
          data.circles.find((circle) => circle.number === state.activeCircle)
        ) {
          const newActiveCircle = data.circles.find(
            (circle) => circle.number === state.activeCircle
          );
          setActiveCircle(newActiveCircle);
          setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
        } else {
          const newActiveCircle = data.circles.find((circle) => circle.status === 'active');
          if (newActiveCircle) {
            setActiveCircle(newActiveCircle);
            setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
          } else {
            setActiveCircle(data.circles[0]);
            setPlayerScoreInput(data.circles[0].fishCount);
          }
        }
      } catch (error) {
        setError(error.message || 'Unknown error');
      } finally {
        setLoading(false);
      }
    };

    fetchUserData();
  }, [code, state]);

  useEffect(() => {
    const socket = socketRef.current;

    // Обработчики событий сокета для обновления данных пользователя
    const handleUserUpdated = (data) => {
      const { updatedUserData, activeCircleNumber } = data;
      if (userData && userData.code === updatedUserData.code) {
        setUserData(updatedUserData);
        const updatedCircle = updatedUserData.circles.find((c) => c.number === activeCircleNumber);
        setActiveCircle(updatedCircle);
        setPlayerScoreInput(updatedCircle.playerGame.fishCount);
      } else if (userData) {
        const currUpdatedActiveCircle = updatedUserData.circles.find(
          (circle) =>
            circle.number === activeCircleNumber &&
            circle.opponentGame.number === userData.player_id &&
            circle.status === 'active'
        );
        let number = activeCircle?.number;
        if (currUpdatedActiveCircle) {
          const updatedCircles = userData.circles.map((circle) => {
            const updatedCircle = updatedUserData.circles.find(
              (c) =>
                c.status === 'active' &&
                c.opponentGame.number === circle.playerGame.number &&
                circle.opponentGame.number === c.playerGame.number &&
                circle.status === 'active'
            );
            if (updatedCircle) {
              number = circle.number;
              return {
                ...circle,
                opponentGame: {
                  ...circle.opponentGame,
                  fishCount: updatedCircle.playerGame.fishCount,
                  approveState: updatedCircle.playerGame.approveState,
                },
                playerGame: {
                  ...circle.playerGame,
                  fishCount: updatedCircle.opponentGame.fishCount,
                  approveState: updatedCircle.opponentGame.approveState,
                },
              };
            }
            return circle;
          });
          setUserData((prevUserData) => ({
            ...prevUserData,
            circles: updatedCircles,
          }));
          const newActiveCircle = updatedCircles.find(
            (circle) =>
              circle.opponentGame.number === currUpdatedActiveCircle.playerGame.number &&
              circle.playerGame.number === currUpdatedActiveCircle.opponentGame.number &&
              circle.status === 'active'
          );
          setActiveCircle(newActiveCircle);
          setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
        }
      }
    };

    const handleAllUsersUpdated = (updatedUsersData) => {
      const currentUser = updatedUsersData.find((user) => user.code === code);
      if (currentUser) {
        setUserData(currentUser);
        let currUpdatedActiveCircle = currentUser.circles.find(
          (circle) => circle.status === 'active'
        );
        if (!currUpdatedActiveCircle) {
          currUpdatedActiveCircle = currentUser.circles.find((circle) => circle.number === 1);
        }
        setActiveCircle(currUpdatedActiveCircle);
        setPlayerScoreInput(currUpdatedActiveCircle.playerGame.fishcount);
        console.log(playerScoreInput);
      }
    };

    const handleDisconnect = () => {
      console.log('Disconnected from server');
    };

    const handleReconnect = () => {
      console.log('Reconnected to server');
      handleReconnection();
    };

    socket.on('allUsersUpdated', handleAllUsersUpdated);
    socket.on('userUpdated', handleUserUpdated);

    socket.on('disconnect', handleDisconnect);
    socket.on('reconnect', handleReconnect);

    return () => {
      socket.off('allUsersUpdated', handleAllUsersUpdated);
      socket.off('userUpdated', handleUserUpdated);
      socket.off('disconnect', handleDisconnect);
      socket.off('reconnect', handleReconnect);
    };
  }, [userData, activeCircle]);

  // Функция обработки повторного подключения
  const handleReconnection = () => {
    resendUnsentActions();
    fetchLatestDataFromServer();
  };

  // Добавляем обработчики событий 'online' и 'offline'
  useEffect(() => {
    function handleOnline() {
      console.log('Интернет подключен');
      handleReconnection();
    }

    function handleOffline() {
      console.log('Интернет отключен');
    }

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  useEffect(() => {
    if (activeCircle) {
      setPlayerScoreInput(activeCircle.playerGame.fishCount);
      setPreviousScoreInput(activeCircle.playerGame.fishCount);
    }
  }, [activeCircle]);

  // Функция повторной отправки несообщенных действий
  const resendUnsentActions = async () => {
    while (unsentActionsQueueRef.current.length > 0) {
      const action = unsentActionsQueueRef.current.shift();
      await action();
    }
    // Добавим задержку и обновление данных с сервера
    setTimeout(fetchLatestDataFromServer, 500);
  };

  // Функция получения последних данных с сервера
  const fetchLatestDataFromServer = async () => {
    try {
      const response = await fetch(`${server_url}/api/user/${code}`);
      if (response.ok) {
        const data = await response.json();
        setUserData(data);
        updateActiveCircle(data);
      } else {
        console.error('Failed to fetch latest data');
      }
    } catch (error) {
      console.error('Error fetching latest data:', error);
    }
  };

  // Функция обновления активного круга
  const updateActiveCircle = (data) => {
    const newActiveCircle = data.circles.find((circle) => circle.status === 'active') || data.circles[0];
    setActiveCircle(newActiveCircle);
    setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
  };

  const handleCircleClick = (circle) => {
    setActiveCircle(circle);
    if (circle.status === 'active') setPlayerScoreInput(circle.playerGame.fishCount);
  };

  const navigateToTournament = () => {
    socketRef.current.on('disconnect', () => {
      console.log('Disconnected from WebSocket server');
    });
    navigate(`/statistics/${code}`);
  };

  // Функция отправки данных на сервер с обработкой ошибок и очередью
  const sendDataToServer = async (action, data) => {
    try {
      let response;
      if (action === 'updateScore') {
        response = await fetch(`${server_url}/api/update-score`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });
      } else if (action === 'updateApproveState') {
        response = await fetch(`${server_url}/api/update-approve-state`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });
      }
  
      if (response.ok) {
        console.log(`${action} успешно отправлено на сервер`);
        // После успешной отправки данных обновляем состояние
        // Можно вызвать fetchLatestDataFromServer или обновить состояние вручную
        await fetchLatestDataFromServer();
      } else {
        throw new Error(`Сервер вернул ошибку при отправке ${action}`);
      }
    } catch (error) {
      console.error(`Ошибка при отправке ${action}:`, error);
      unsentActionsQueueRef.current.push(() => sendDataToServer(action, data));
    }
  };

  // Модифицированная функция обновления состояния подтверждения
  const updateApproveState = async () => {
    if (
      !activeCircle ||
      activeCircle.status !== 'active' ||
      !userData ||
      typeof activeCircle.playerGame.fishCount !== 'number' ||
      isNaN(activeCircle.playerGame.fishCount) ||
      typeof activeCircle.opponentGame.fishCount !== 'number' ||
      isNaN(activeCircle.opponentGame.fishCount)
    )
      return;

    // Обновляем локальные данные
    const activeCircleIndex = userData.circles.findIndex(
      (circle) => circle.number === activeCircle.number && circle.status === 'active'
    );
    if (activeCircleIndex !== -1) {
      let updatedUserData = { ...userData };
      // Подготавливаем данные для отправки
      const dataToSend = { userData: updatedUserData, activeCircleNumber: activeCircle.number };

      // Отправляем данные на сервер
      sendDataToServer('updateApproveState', dataToSend);
    }
  };

  // Модифицированная функция обработки изменения ввода очков
  const handleScoreInputChange = (e) => {
    let value = e.target.value;
    if (value === '' || isNaN(value) || parseInt(value) > 99) {
      value = 0;
    } else {
      value = parseInt(value);
    }
    setPlayerScoreInput(value);
  };

  const handleEnterButtonClick = () => {
    let newPlayerScoreInput;
    if (playerScoreInput === '' || isNaN(playerScoreInput)) {
      newPlayerScoreInput = 0;
    } else {
      newPlayerScoreInput = parseInt(playerScoreInput, 10);
    }

    if (newPlayerScoreInput !== previousScoreInput) {
      const activeCircleIndex = userData.circles.findIndex(
        (circle) => circle.number === activeCircle.number && circle.status === 'active'
      );
      if (activeCircleIndex !== -1) {
        let updatedUserData = { ...userData };
        updatedUserData.circles[activeCircleIndex].playerGame.fishCount = newPlayerScoreInput;
        setPlayerScoreInput(newPlayerScoreInput);
        setUserData(updatedUserData);
        setActiveCircle(updatedUserData.circles[activeCircleIndex]);

        // Подготовка данных для отправки
        const dataToSend = { userData: updatedUserData, activeCircleNumber: activeCircle.number };

        // Отправка данных на сервер
        sendDataToServer('updateScore', dataToSend);

        // Обновляем previousScoreInput
        setPreviousScoreInput(newPlayerScoreInput);
      }
    }
  };

  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

    return (
        <article className="playerCard">
            <div className='kostul'></div>
            <div className='kostul2'></div>
            <div className='kostul3'></div>
            <div className="mainRectangle"></div>
            <div className="header"></div>
            <div className="triangle"><span>VS</span></div>
            <div className={`redRectangle ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : ''}`}>
                {`#${activeCircle?.opponentGame.number} ${activeCircle?.opponentGame.name}: ${activeCircle?.opponentGame.total_points} pts`}
            </div>
            <div className="sectorInfo">
                {`Sector ${activeCircle?.playerGame.sector}${(activeCircle?.playerGame.number % 2 === activeCircle?.index_circle % 2) ? 'R' : 'L'}`}
            </div>
            <div
                className={`bottomRectangle ${activeCircle?.status === "inactive" || activeCircle?.status === "completed" ? 'inactive' : `state-${activeCircle?.playerGame.approveState}`}`}
                onClick={updateApproveState}
            >
                {activeCircle?.status === "completed" ? `+ ${activeCircle?.playerGame.points} Pts` : activeCircle?.status === "inactive" ? 'Approve' : activeCircle?.playerGame.approveState === 1 ? 'Approve' : activeCircle.playerGame.approveState === 2 ? 'Disapprove' : activeCircle.playerGame.approveState === 3 ? 'Approve' : 'Disapprove'}
            </div>
            <div className="playerNameContainer">
                <div className="playerName">{`#${activeCircle?.playerGame.number} ${activeCircle?.playerGame.name}: ${activeCircle?.playerGame.total_points} pts`}</div>
                <img src={vectorImage} alt='' className="vectorImage" onClick={navigateToTournament} />
            </div>
            <div className="circleContainerlayout">
                <div className="thickerWhiteLine"></div>
                <div className="circleContainer">
                    {userData.circles.map((circle) => (
                        <div
                            key={circle.number}
                            className={`circle ${circle.status} ${
                                activeCircle?.number === circle.number ? 'highlighted' : ''
                            }`}
                            onClick={() => handleCircleClick(circle)}
                        >
                            <span>{circle.index_circle}</span>
                            <span>
                                {circle.playerGame.fishCount}:{circle.opponentGame.fishCount}
                            </span>
                            {activeCircle?.number === circle.number && (
                                <div className="triangle-under-circle"></div>
                            )}
                        </div>
                    ))}
                </div>
            </div>
            <div className="whiteRectangleLeft">
                <div className="playerNumberLeft">{`#${activeCircle?.playerGame.number}`}</div>
            </div>
            <div className={`blueRectangleLeft ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : 'active'}`}>
                {activeCircle?.status === "completed" || activeCircle?.status === "inactive" ? (
                    <div className="score">{activeCircle?.playerGame.fishCount}</div>
                ) : (activeCircle?.playerGame.approveState === 1 || activeCircle?.playerGame.approveState === 2) ? (
                    <>
                    <input
                      type="tel"
                      value={playerScoreInput}
                      onFocus={() => setPlayerScoreInput('')}
                      onChange={handleScoreInputChange}
                      className="scoreInputActive"
                    />
                    <button onClick={handleEnterButtonClick} className="enterButton">OK</button>
                    </>
                ) : (
                    <input
                        type="tel"
                        value={playerScoreInput}
                        readOnly
                        className="scoreInput"
                    />
                )
            }
            </div>
                <div className="whiteRectangleRight">
                    <div className="playerNumberRight">{`#${activeCircle?.opponentGame.number}`}</div>
                </div>
                <div className={`blueRectangleRight ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : ''}`}>
                    <div className="score">
                    {activeCircle?.opponentGame.fishCount}
                </div>
            </div>
        </article>
    );
};

export default Tournament;
Это клиент - страница
/* Styles for completed state */
@font-face {
    font-family: 'Arimo';
    src: url('./fonts/Arimo-Medium.ttf') format('truetype');
    }

.redRectangle.completed {
    background-color: #32404d;
}

.blueRectangleLeft.completed, .blueRectangleRight.completed {
    background-color: #32404d;
}

.bottomRectangle.completed {
    background-color: #666666;
}

.bottomRectangle.state-0 {
    background-color: #666666;
    color: #fff;
    cursor: not-allowed;
}

.bottomRectangle.state-1 {
    background-color: #ea5558;
}

.bottomRectangle.state-2 {
    background: linear-gradient(to right, #666666 50%, #ea5558 50%);
    color: #fff;
}

.bottomRectangle.state-3 {
    background: linear-gradient(to right, #ea5558 50%, #666666 50%);
    color: #fff;
}

.bottomRectangle.state-4 {
    background-color: #666666;
    color: #fff;
}

/* Styles for inactive state */
.redRectangle.inactive {
    background-color: #666666; /* Light gray color */
}

.blueRectangleLeft.inactive, .blueRectangleRight.inactive {
    background-color: #666666; /* Ligh gray color */
}

.bottomRectangle.inactive {
    background-color: #666666; /* Light gray color */
    color: #fff; /* Ensure text is still visible */
    cursor: not-allowed; /* Indicate the button is not clickable */
}

/* Other existing styles... */
.playerCard {
    position: relative;
    display: flex;
    width: 100%;
    height: 100%;
    background-color: #d9d9d9;
    overflow-x: hidden; /* Prevent horizontal overflow */
}

.playerNameContainer {
    position: absolute;
    top: 2%;
    left: 0%;
    right: 3%;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.vectorImage {
    max-height: 100%;
    max-width: 20%;
    margin-left: auto;
}

.header {
    position: absolute;
    width: 100%;
    height: 23%;
    background-color: #658199;
    top: 0;
    left: 0;
}

.mainRectangle {
    position: absolute;
    width: 95%;
    height: 18%;
    background-color: #fff;
    top: 21%;
    left: 2.5%;
    border-radius: 20px;
}

.triangle {
    position: absolute;
    width: 0;
    height: 0;
    border-left: 10vh solid transparent;
    border-right: 10vh solid transparent;
    border-top: 7vh solid #658199;
    top: 23%;
    left: 50%;
    transform: translateX(-50%);
}

.triangle span {
    position: absolute;
    top: -6vh;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    font-size: 3vh;
    font-weight: 500;
    font-family: 'Arimo';
    line-height: 3vh;
}

.redRectangle {
    position: absolute;
    width: 92%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    height: 5%;
    background-color: #ea5558;
    top: 28%;
    left: 4%;
    color: #fff;
    text-align: center;
    line-height: 5vh;
    font-size: 2.8vh;
    font-weight: 500;
    font-family: 'Arimo';
    border-radius: 1.5vh;
}

.sectorInfo {
    position: absolute;
    width: 94%;
    height: 5%;
    top: 34%;
    left: 3%;
    color: #658199;
    text-align: center;
    line-height: 4vh;
    font-size: 4vh;
    font-weight: 500;
    font-family: 'Arimo';
    
}

.bottomRectangle {
    position: absolute;
    width: 95%;
    height: 7%;
    background-color: #cc494c;
    bottom: 1%;
    left: 2.5%;
    color: #fff;
    text-align: center;
    font-size: 2.3vh;
    font-family: 'Arimo';
    line-height: 7vh;
    border-radius: 3vh;
}

.playerName {
    position: absolute;
    margin-right: auto;
    width: 92%;
    top: 2%;
    left: 4%;
    font-size: 3vh;
    font-family: 'Arimo';
    line-height: 3vh;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.circleContainer {
    display: flex;
    overflow-x: auto; /* Allow horizontal scrolling */
    -ms-overflow-style: none;
    scrollbar-width: none;
    width: 100%;
    overflow-y: hidden; /* Hide vertical scrollbar */
    white-space: nowrap; /* Prevent wrapping to multiple lines */
    box-sizing: border-box; /* Include padding and border in the element's total width and height */
}
.circleContainerlayout {
    display: flex;
    padding: 10px 0;
    height: 20%;
    width: 94%;
    position: absolute;
    top: 7%;
    left: 3%;
    right: 3%;
}

.circle {
    flex: 0 0 auto; /* Prevent circles from shrinking or growing */
    width: 7.5vh;
    height: 7.5vh;
    background-color: #efefef;
    border: 1px solid #d9d9d9;
    border-radius: 50%;
    margin-right: 2%; /* Add space between circles */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1vh;
    font-weight: 500;
    font-family: 'Arimo';
    color: #658199;
    scroll-snap-align: center; /* Center snapping for each circle */
    position: relative;
}

.circle.completed {
    background-color: #32404d;
    border-color: #32404d;
    color: #fff;
}

.circle.active {
    background-color: #ea5558;
    border-color: #722628;
    color: #fff;
}

.circle span {
    display: block;
    text-align: center;
    line-height: 1.5; /* Adjust line-height for spacing */
    font-size: 2vh;
    font-family: 'Arimo';
}

.circle span:first-child {
    margin-bottom: 0.5vw; /* Move top number up */
}

.triangle-under-circle {
    position: absolute;
    top: 80%;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border: 2vh solid transparent;
    border-bottom: 4vh solid #ea5558; /* Adjust triangle size */
}

.thickerWhiteLine {
    position: absolute;
    top: 55%;
    width: 100%;
    height: 0.7vh; /* Сделаем линию толще */
    border-radius: 3vh;
    background-color: #E7E0EC;
     /* Ensure it is above other elements */
}

.whiteRectangleLeft {
    position: absolute;
    width: 35%;
    height: 39%;
    background-color: #fff;
    top: 43%;
    left: 6%;
    border-radius: 2vh;
}

.blueRectangleLeft {
    position: absolute;
    width: 42%;
    height: 39%;
    background-color: #658199;
    top: 51%;
    left: 3%;
    border-radius: 3vh;
    display: flex;
    align-items: center;
    justify-content: center;
  }

.whiteRectangleRight {
    position: absolute;
    width: 35%;
    height: 39%;
    background-color: #fff;
    top: 43%;
    left: 57.5%;
    border-radius: 2vh;
}

.blueRectangleRight {
    position: absolute;
    width: 42%;
    height: 39%;
    background-color: #658199;
    top: 51%;
    left: 54%;
    border-radius: 3vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.playerNumberLeft, .playerNumberRight {
    position: absolute;
    left: 50%;
    top: 1vh;
    transform: translateX(-50%);
    padding: 0.5%;
    border-radius: 20px;
    font-size: 5vh;
    font-weight: 500;
    font-family: 'Arimo';
    color: #32404d;
    text-align: center;
}

.score {
    font-size: calc(min(31vw, 25vh));
    color: #fff;
    text-align: center;
    font-family: 'Arimo';
}

.scoreInput {
    width: 80%;
    height: 80%;
    font-size: calc(min(31vw, 25vh));
    text-align: center;
    color: #fff;
    background-color: #658199;
    border: none;
    outline: none;
    font-family: 'Arimo';
}

.scoreInputActive {
    font-size: calc(min(31vw, 25vh));
    white-space: nowrap; 
    text-align: center;
    color: #fff;
    background-color: rgba(101, 129, 153, 0);
    border: none;
    border-width: 0;
    outline: none;
    font-family: 'Arimo';
}

.kostul {
    position: absolute;
    width: 9%;
    height: 40%;
    background-color: #d9d9d9;
    top: 51%;
    left: 45%;
    z-index: 1;
}

.kostul2 {
    position: absolute;
    width: 3.1%;
    height: 40%;
    background-color: #d9d9d9;
    top: 51%;
    left: 0%;
    z-index: 1;
}
.kostul3 {
    position: absolute;
    width: 4%;
    height: 40%;
    background-color: #d9d9d9;
    top: 51%;
    left: 96%;
    z-index: 1;
} 
  .enterButton {
    position: absolute;
    width: 100%;
    height: 20%;
    top: 80%;
    left: 0%;
    border: none;
    border-radius: 3vh;
    font-size: 2.5vh;
    font-family: 'Arimo';
    color: #fff;
    background-color: #ea5558;
  }
  
  .enterButton:active {
    background-color: #666666;
  }
Это ее стили
Я хочу, чтобы при начале редактирования числа в bluerectangleleft сам bluerectangleleft увеличивался равномерно во все стороны от центра и появлялась кнопка ОК, после нажатия на которую bluerectangleleft возвращался бы в начальное положение и кнопка ОК пропадала бы