
using Marro.PacManUdon;
using Newtonsoft.Json.Linq;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class NetworkManagerSyncTester : UdonSharpBehaviour
{
    [SerializeField] NetworkManager networkManager1;
    [SerializeField] GridMover[] gridMovers1;
    [SerializeField] NetworkManager networkManager2;
    [SerializeField] GridMover[] gridMovers2;

    [SerializeField] Animator debugImageToIndicateSynced;

    private int[] captureTimes = new int[1000];
    private Vector2[][] positionCaptures = new Vector2[1000][];
    private int ownerIndex = -1;
    private int remoteIndex = 0;
    private int previousCaptureTime = -1;

    public void Update()
    {
        if (!networkManager1.Synced || !networkManager2.Synced)
        {
            ownerIndex = -1;
            remoteIndex = 0;
            return;
        }

        var ownerTime = networkManager1.SyncedTimeTicks;

        if (ownerTime > previousCaptureTime)
        {
            IncrementIndex(ref ownerIndex);
            captureTimes[ownerIndex] = ownerTime;
            previousCaptureTime = ownerTime;
            positionCaptures[ownerIndex] = GetPositions(gridMovers1);
        }

        var remoteTime = networkManager2.SyncedTimeTicks;

        while (captureTimes[remoteIndex] < remoteTime && remoteIndex != ownerIndex)
        {
            DiscardCapture();
        }

        //Debug.Log($"ownerTime: {ownerTime}, remoteTime: {remoteTime}, ownerIndex: {ownerIndex} ({captureTimes[ownerIndex]}), remoteIndex: {remoteIndex} ({captureTimes[remoteIndex]})");

        if (captureTimes[remoteIndex] == remoteTime)
        {
            bool equal = IsEqual(remoteIndex, remoteTime);
            SetIndicator(equal);

            DiscardCapture();
        }
    }

    private void DiscardCapture()
    {
        positionCaptures[remoteIndex] = null;
        IncrementIndex(ref remoteIndex);
    }

    private bool IsEqual(int index, int time)
    {
        var equal = true;

        var positions1 = positionCaptures[index];
        var positions2 = GetPositions(gridMovers2);
        for (int i = 0; i < positions1.Length; i++)
        {
            var gridMover1 = gridMovers1[i];
            var gridMover1Position = positions1[i];

            var gridMover2 = gridMovers2[i];
            var gridMover2Position = positions2[i];

            if (gridMover1Position != gridMover2Position)
            {
                Debug.LogWarning($"{nameof(NetworkManagerSyncTester)} Desync found at {time} in {gridMover1.name}:\n {gridMover1Position} (local) != {gridMover2Position} (remote)");
                //networkManager1.Pause();
                //networkManager2.Pause();
                equal = false;
            }
        }

        return equal;
    }

    private void SetIndicator(bool value)
    {
        if (debugImageToIndicateSynced != null)
        {
            debugImageToIndicateSynced.SetFloat("Color", value ? 1 : 0);
        }
    }

    private static Vector2[] GetPositions(GridMover[] gridMovers)
    {
        var length = gridMovers.Length;
        var positions = new Vector2[length];

        for (int i = 0; i < length; i++)
        {
            positions[i] = gridMovers[i].GetPosition(); 
        }

        return positions;
    }

    private void IncrementIndex(ref int index)
    {
        if (index >= positionCaptures.Length - 1)
        {
            index = 0;
        }
        else
        {
            index++;
        }
    }
}
