using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CloudPointRpc;
using UnityEngine;

public class RpcFunctions : MonoBehaviour 
{
    private static Queue<Task> _callbackTasks = new Queue<Task>();
    private static BlendShaderController controller;
    private static CancellationTokenSource cts;

    void Start()
    {
        controller = GetComponent<BlendShaderController>();
        cts = new CancellationTokenSource();

        CrpcExtensions.CrpcInit("config.json");

        CrpcExtensions.CrpcAddMethod(RpcGetCloudPoint, "get_cloud_point");
        CrpcExtensions.CrpcAddMethod(RpcGetImage, "get_image");
        CrpcExtensions.CrpcAddMethod(RpcGetIntrinsicsLeft, "get_intrinsics_left");
        CrpcExtensions.CrpcAddMethod(RpcGetIntrinsicsRight, "get_intrinsics_right");
        CrpcExtensions.CrpcAddMethod(RpcGetExtrinsicsLeft, "get_extrinsics_left");
        CrpcExtensions.CrpcAddMethod(RpcGetExtrinsicsRight, "get_extrinsics_right");

        Debug.Log("[RpcFunctions] Initialized and methods added");
    }

    private void OnDestroy()
    {
        lock (_callbackTasks)
        {
            _callbackTasks.Clear();
        }
        cts.Cancel();
        CrpcServerApi.crpc_deinit();
    }

    private void Update()
    {
        lock (_callbackTasks)
        {
            while (_callbackTasks.Count > 0)
            {
                var task = _callbackTasks.Dequeue();
                task.RunSynchronously();
            }
        }
    }

    public static IntPtr RpcGetCloudPoint(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();
        var tcs = new TaskCompletionSource<string>();

        var task = new Task(() => {
            Debug.Log($"[RpcTest] Callback received: {message}");
            controller.GetDistArray(tcs);
                }, cts.Token);

        lock (_callbackTasks)
        {
            _callbackTasks.Enqueue(task);
        }

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }
        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }
    
    public static IntPtr RpcGetImage(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();

        var tcs = new TaskCompletionSource<string>();
        var task = new Task(() =>
        {
            string result = controller.GetCombinedTexturesAsBase64Json();
            tcs.SetResult(result);
        });

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }

        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }

    public static IntPtr RpcGetIntrinsicsLeft(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();

        var tcs = new TaskCompletionSource<string>();
        var task = new Task(() =>
        {
            string result = controller.GetLeftIntrinsicParametersAsBase64();
            tcs.SetResult(result);
        });

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }

        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }

    public static IntPtr RpcGetIntrinsicsRight(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();

        var tcs = new TaskCompletionSource<string>();
        var task = new Task(() =>
        {
            string result = controller.GetRightIntrinsicParametersAsBase64();
            tcs.SetResult(result);
        });

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }

        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }

    public static IntPtr RpcGetExtrinsicsLeft(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();

        var tcs = new TaskCompletionSource<string>();
        var task = new Task(() =>
        {
            string result = controller.GetLeftExtrinsicParametersAsBase64();
            tcs.SetResult(result);
        });

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }

        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }

    public static IntPtr RpcGetExtrinsicsRight(IntPtr rpcString)
    {
        var rpc = new RpcString(rpcString);
        var message = rpc.Data;
        rpc.Dispose();

        var tcs = new TaskCompletionSource<string>();
        var task = new Task(() =>
        {
            string result = controller.GetRightExtrinsicParametersAsBase64();
            tcs.SetResult(result);
        });

        try
        {
            task.Wait(cts.Token);
            tcs.Task.Wait(cts.Token);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("Waiting was canceled");
        }

        var responce = new RpcString(tcs.Task.Result);
        return responce.Handle;
    }
}
