package com.ccwangluo.ccim.audio;

import android.Manifest;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import com.ccwangluo.ccim.CCIMClient;
import com.ccwangluo.ccim.listener.AudioRoomListener;
import com.ccwangluo.ccim.modle.User;
import com.ccwangluo.ccim.util.ErrorCode;
import com.github.helloiampau.janus.generated.Bundle;
import com.github.helloiampau.janus.generated.Janus;
import com.github.helloiampau.janus.generated.JanusCommands;
import com.github.helloiampau.janus.generated.JanusData;
import com.github.helloiampau.janus.generated.JanusError;
import com.github.helloiampau.janus.generated.JanusEvent;
import com.github.helloiampau.janusclientsdk.JanusConfImpl;
import com.github.helloiampau.janusclientsdk.JanusDelegate;
import com.github.helloiampau.janusclientsdk.JanusFactory;
import com.github.helloiampau.janusclientsdk.rtc.AppRTCAudioManager;
import com.github.helloiampau.janusclientsdk.rtc.MediaBundle;
import com.google.gson.Gson;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import org.webrtc.AudioTrack;
import org.webrtc.DataChannel;
import org.webrtc.EglBase;
import org.webrtc.Logging;
import org.webrtc.PeerConnection;
import java.util.List;
import java.util.logging.Logger;

public class JanusService extends JanusDelegate {
    private final Logger logger = Logger.getLogger(CCIMClient.class.getName());
    private Janus _janus;
    private EglBase _rootEgl;
    private User user;
    private Integer roomId;
    private Boolean isJoin = false;
    private AudioRoomListener callback;

    //    private AudioManager audioManager;
    private AudioTrack audioTrack;
    private int teamId;

    private AppRTCAudioManager audioManager;

    public JanusService(Context context, Integer roomId, User user, int teamId, AudioRoomListener callback) {
        audioManager = AppRTCAudioManager.create(context);
        this.user = user;
        this.roomId = roomId;
        this.callback = callback;
        this.teamId = teamId;
    }


    public void start(Context context, JanusConfImpl conf) {
        Dexter.withContext(context).withPermissions(Manifest.permission.RECORD_AUDIO).withListener(new MultiplePermissionsListener() {
            @Override
            public void onPermissionsChecked(MultiplePermissionsReport report) {
                JanusFactory factory = new JanusFactory();
                _janus = factory.create(conf, JanusService.this, context.getApplicationContext());

                Logging.enableLogToDebugOutput(Logging.Severity.LS_VERBOSE);

                _rootEgl = factory.rootEgl();
                _janus.init();

            }

            @Override
            public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                callback.onJoinFailed(ErrorCode.ERROR_PERMISSION_DENIE);
            }
        }).check();
    }

    public void stop() {
        state = State.NORMAL_DISCONNECTED;
        if (_janus != null) {
            this._janus.close();
        }
    }

    public void setLocalAudio(boolean enable) {
        if (audioTrack != null) {
            audioTrack.setEnabled(enable);
        }
    }

    public void targetWorld(boolean enable) {
        if (isJoin) {
            Bundle payload = Bundle.create();
            payload.setBool("world", enable);
            this._janus.dispatch(JanusCommands.SET_TARGET, payload);
        }
    }


    @Override
    public void onClose() {
        logger.info("close");
        if (audioManager != null) {
            CCIMClient.getInstance().handler.post(new Runnable() {
                @Override
                public void run() {
                    audioManager.stop();
                }
            });
        }
    }

    @Override
    public void onError(JanusError error, Bundle context) {
        logger.info("onError  " + error.toString());
        callback.onError(ErrorCode.ERRORCODE_NOT_EXISTS);
    }

    @Override
    public void onReady() {
        logger.info("onReady");
        Bundle payload = Bundle.create();
        payload.setInt("room", roomId);
        payload.setString("display", new Gson().toJson(user));
        payload.setInt("team", teamId);
        this._janus.dispatch(JanusCommands.JOIN, payload);
        CCIMClient.getInstance().handler.post(new Runnable() {
            @Override
            public void run() {
                audioManager.start((selectedAudioDevice, availableAudioDevices) -> {

                });
            }
        });
    }

    @Override
    public void onHangup(String reason) {

    }


    @Override
    public void onMediaChanged(MediaBundle media) {
        if (media.localAudioTrack() != null) {
            audioTrack = media.localAudioTrack();
            if (!CCIMClient.getInstance().checkMutedExpired()) {
                audioTrack.setEnabled(false);
            }
        }
    }

    @Override
    public void onDatachannelMessage(DataChannel.Buffer buffer) {

    }

    private State state = State.INIT;

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        logger.info("onIceConnectionChange");
        if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
            stop();
            if (state != State.NORMAL_DISCONNECTED) {
                callback.onError(ErrorCode.NET_ERROR);
                state = State.ERROR_DISCONNECTED;
            }
            callback.onExit();
            new Handler(Looper.getMainLooper()).postDelayed(() -> {
                if (state != State.ERROR_DISCONNECTED && state != State.NORMAL_DISCONNECTED) {
                    return;
                }
                _janus.dispatch(JanusCommands.FORCE_DESTROY, Bundle.create());
            }, 5000);
        }
    }

    private enum State {
        INIT,
        STARTED,
        NORMAL_DISCONNECTED,
        ERROR_DISCONNECTED,
        STOPPED
    }

    @Override
    public String onOffer(String sdp) {
        return sdp;
    }

    @Override
    public String onAnswer(String sdp) {
        return sdp;
    }

    @Override
    public void onEvent(JanusEvent event, Bundle context) {
        JanusData data = event.data();
        logger.info("onEvent  " + data.getString("janus", ""));
        logger.info("onEvent  " + data.getString("videoroom", ""));
        if (data.getString("janus", "").equals("error") && context.getString("command", "").equals(JanusCommands.JOIN)) {
            logger.info("加入失败");
            if (callback != null) {
                callback.onJoinFailed(ErrorCode.JOIN_AUDIO_FAILED);
            }
            return;
        }
        if (data.getString("videoroom", "").equals("event") && data.getInt("error_code", -1) == 426) {
            callback.onJoinFailed(ErrorCode.JOIN_AUDIO_FAILED_NO_SUCH_ROOM);
            return;
        }
        if (data.getString("videoroom", "").equals("joined")) {
            if (!isJoin) {
                isJoin = true;
                Bundle payload = Bundle.create();
                payload.setBool("audio", true);
                payload.setBool("video", false);
                payload.setBool("data", false);
                this._janus.dispatch(JanusCommands.PUBLISH, payload);
                logger.info("加入成功");
                List<JanusData> publishers = data.getList("publishers");
                subscribePublishers(publishers);
                if (callback != null) {
                    callback.onJoinSuccess();
                }
            }
            return;
        }

        List<JanusData> publishers = data.getList("publishers");
        if (publishers.size() > 0) {
            subscribePublishers(publishers);
            return;
        }
    }

    private void subscribePublishers(List<JanusData> publishers) {
        if (publishers.size() > 0) {
            for (JanusData publisher : publishers) {
                Bundle payload = Bundle.create();
                payload.setInt("room", roomId);
                payload.setInt("feed", publisher.getInt("id", -1));
//                payload.setInt("feed", publisher.getString("display", ""));
                payload.setInt("team", teamId);
//                Publisher pub = new Publisher(publisher);
//                publishersMap.put(pub.handleId, pub);

                this._janus.dispatch(JanusCommands.SUBSCRIBE, payload);
            }
        }
    }


}
