using UnityEngine;
using WebSocketSharp;
using System.Threading;
using Concentus.Structs;

public class OpusVoiceReceiverWithBuffer : MonoBehaviour
{
    private WebSocket ws;
    private AudioSource audioSource;
    private OpusDecoder decoder;

    private const int sampleRate = 16000;
    private const int channels = 1;

    private const int clipLengthSeconds = 5; // طول کل AudioClip به ثانیه
    private AudioClip audioClip;

    private float[] audioBuffer;
    private int bufferWritePos = 0;
    private int bufferReadPos = 0;
    private int bufferSize;

    private object bufferLock = new object();

    void Start()
    {
        audioSource = gameObject.AddComponent<AudioSource>();
        audioSource.loop = true;

        decoder = new OpusDecoder(sampleRate, channels);

        bufferSize = sampleRate * clipLengthSeconds; // اندازه بافر به تعداد نمونه ها
        audioBuffer = new float[bufferSize];

        audioClip = AudioClip.Create("VoiceStream", bufferSize, channels, sampleRate, true, OnAudioRead, OnAudioSetPosition);
        audioSource.clip = audioClip;
        audioSource.Play();

        ws = new WebSocket("ws://192.168.31.10:8765");
        ws.OnMessage += OnMessageReceived;
        ws.Connect();
    }

    private void OnMessageReceived(object sender, MessageEventArgs e)
    {
        // دیکد کردن داده اوپوس
        short[] pcm = new short[960]; // 20ms frame at 16kHz
        int decodedSamples = decoder.Decode(e.RawData, 0, e.RawData.Length, pcm, 0, pcm.Length, false);

        float[] floatSamples = new float[decodedSamples];
        for (int i = 0; i < decodedSamples; i++)
            floatSamples[i] = pcm[i] / (float)short.MaxValue;

        // نوشتن در بافر حلقه‌ای امن در برابر چند Thread
        lock (bufferLock)
        {
            for (int i = 0; i < decodedSamples; i++)
            {
                audioBuffer[bufferWritePos] = floatSamples[i];
                bufferWritePos = (bufferWritePos + 1) % bufferSize;

                // در صورت پر شدن بافر، خواندن را جلو می‌بریم (داده‌های قدیمی حذف می‌شوند)
                if (bufferWritePos == bufferReadPos)
                {
                    bufferReadPos = (bufferReadPos + 1) % bufferSize;
                }
            }
        }
    }

    // این تابع توسط AudioSource برای خواندن داده‌های صوتی فراخوانی می‌شود
    void OnAudioRead(float[] data)
    {
        lock (bufferLock)
        {
            for (int i = 0; i < data.Length; i++)
            {
                if (bufferReadPos != bufferWritePos)
                {
                    data[i] = audioBuffer[bufferReadPos];
                    bufferReadPos = (bufferReadPos + 1) % bufferSize;
                }
                else
                {
                    // اگر بافر خالی باشد، سکوت پخش می‌کنیم
                    data[i] = 0f;
                }
            }
        }
    }

    void OnAudioSetPosition(int newPosition)
    {
        // این تابع باید باشد ولی در اینجا کاری انجام نمی‌دهیم
    }

    private void OnDestroy()
    {
        ws?.Close();
    }
}
