package com.reactnativezoom.videosdk.broadcaststream;

import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

import java.nio.ByteBuffer;

import us.zoom.sdk.ZoomVideoSDKAudioRawData;
import us.zoom.sdk.ZoomVideoSDKBroadcastStreamingAudioCallback;

/**
 * Plays incoming broadcast audio (16-bit signed PCM) through an
 * {@link AudioTrack} routed to the music stream.
 *
 * The SDK does NOT auto-play broadcast audio — this class is the sink.
 * Lazy-creates the AudioTrack on the first frame, recreates it if the
 * sample rate or channel count changes.
 */
public class BroadcastStreamingAudioPlayer implements ZoomVideoSDKBroadcastStreamingAudioCallback {

    private static final String TAG = "BroadcastStreamingAudioPlayer";

    private AudioTrack audioTrack;
    private int currentSampleRate = -1;
    private int currentChannelCount = -1;

    public synchronized void stop() {
        if (audioTrack != null) {
            try {
                audioTrack.pause();
                audioTrack.flush();
                audioTrack.stop();
            } catch (IllegalStateException ignored) {
            }
            try {
                audioTrack.release();
            } catch (Exception ignored) {
            }
            audioTrack = null;
        }
        currentSampleRate = -1;
        currentChannelCount = -1;
    }

    @Override
    public synchronized void onAudioRawDataReceived(ZoomVideoSDKAudioRawData rawData) {
        if (rawData == null) {
            return;
        }
        int sampleRate = rawData.getSampleRate();
        int channelCount = rawData.getChannelNum();
        int bufferLen = rawData.getBufferLen();
        if (sampleRate <= 0 || channelCount <= 0 || bufferLen <= 0) {
            return;
        }

        ensureAudioTrack(sampleRate, channelCount);
        if (audioTrack == null) {
            return;
        }

        // ZoomVideoSDKAudioRawData exposes a ByteBuffer view of 16-bit PCM.
        ByteBuffer buffer = rawData.getBuffer();
        if (buffer == null) {
            return;
        }

        // The buffer's position/limit may be set by the SDK; copy the
        // payload into a stable byte[] for AudioTrack#write.
        byte[] copy;
        try {
            int remaining = Math.min(buffer.remaining(), bufferLen);
            if (remaining <= 0) {
                return;
            }
            copy = new byte[remaining];
            buffer.get(copy, 0, remaining);
        } catch (Exception e) {
            Log.w(TAG, "audio buffer copy failed: " + e.getMessage());
            return;
        }

        try {
            audioTrack.write(copy, 0, copy.length);
        } catch (IllegalStateException e) {
            Log.w(TAG, "AudioTrack write failed: " + e.getMessage());
        }
    }

    private void ensureAudioTrack(int sampleRate, int channelCount) {
        if (audioTrack != null
                && currentSampleRate == sampleRate
                && currentChannelCount == channelCount) {
            return;
        }
        // (Re)create AudioTrack when format changes.
        stop();

        int channelMask = (channelCount == 2)
                ? AudioFormat.CHANNEL_OUT_STEREO
                : AudioFormat.CHANNEL_OUT_MONO;
        int minBuffer = AudioTrack.getMinBufferSize(sampleRate, channelMask, AudioFormat.ENCODING_PCM_16BIT);
        if (minBuffer <= 0) {
            Log.w(TAG, "invalid AudioTrack minBuffer for sampleRate=" + sampleRate + " channels=" + channelCount);
            return;
        }
        // Use a generous buffer (4x min) to absorb jitter without underruns.
        int trackBuffer = minBuffer * 4;

        try {
            audioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                            .setSampleRate(sampleRate)
                            .setChannelMask(channelMask)
                            .build())
                    .setBufferSizeInBytes(trackBuffer)
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .build();
            audioTrack.play();
            currentSampleRate = sampleRate;
            currentChannelCount = channelCount;
        } catch (Exception e) {
            Log.w(TAG, "AudioTrack init failed: " + e.getMessage());
            audioTrack = null;
        }
    }
}
