package com.yidianling.avchatkit.controll;

import android.app.Activity;
import android.content.Context;
import android.util.Pair;
import android.view.View;

import com.netease.nimlib.sdk.ResponseCode;
import com.netease.nimlib.sdk.avchat.AVChatCallback;
import com.netease.nimlib.sdk.avchat.AVChatManager;
import com.netease.nimlib.sdk.avchat.constant.AVChatControlCommand;
import com.netease.nimlib.sdk.avchat.constant.AVChatType;
import com.netease.nimlib.sdk.avchat.model.AVChatData;
import com.netease.nimlib.sdk.avchat.model.AVChatNotifyOption;
import com.netease.nimlib.sdk.avchat.model.AVChatParameters;
import com.netease.nimlib.sdk.avchat.video.AVChatCameraCapturer;
import com.netease.nimlib.sdk.avchat.video.AVChatVideoCapturerFactory;
import com.ydl.ydlcommon.utils.log.AliYunLogConfig;
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper;
import com.yidianling.avchatkit.AVChatKit;
import com.yidianling.avchatkit.common.log.LogUtil;
import com.yidianling.avchatkit.common.widgets.MultiSelectDialog;
import com.yidianling.avchatkit.config.AVChatConfigs;
import com.yidianling.avchatkit.config.AVPrivatizationConfig;
import com.yidianling.avchatkit.constant.AVChatExitCode;
import com.yidianling.avchatkit.constant.CallStateEnum;
import com.yidianling.avchatkit.module.AVChatControllerCallback;
import com.yidianling.avchatkit.module.AVSwitchListener;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.im.R;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 音视频控制器：用于实现音视频拨打接听，音视频切换的具体功能实现
 * Created by winnie on 2017/12/10.
 */

public class AVChatController {
    private static final String TAG = AVChatController.class.getSimpleName();

    protected Context context;
    private long timeBase = 0;
    protected AVChatData avChatData;
    private AVChatCameraCapturer mVideoCapturer;
    private AVChatConfigs avChatConfigs;


    public AtomicBoolean isCallEstablish = new AtomicBoolean(false);
    private boolean destroyRTC = false;
    private boolean isRecording = false;

    private boolean needRestoreLocalVideo = false;
    private boolean needRestoreLocalAudio = false;

    List<Pair<String, Boolean>> recordList = new LinkedList<Pair<String, Boolean>>();

    public interface RecordCallback {
        void onRecordUpdate(boolean isRecording);
    }


    /**
     * *************************** 初始化 ************************
     */

    public AVChatController(Context context, AVChatData avChatData) {
        this.context = context;
        this.avChatData = avChatData;
        this.avChatConfigs = new AVChatConfigs(context);
    }

    /**
     * 恢复视频和语音发送
     */
    public void resumeVideo() {
        AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "恢复视频和语音发送");
        if (needRestoreLocalVideo) {
            AVChatManager.getInstance().muteLocalVideo(false);
            needRestoreLocalVideo = false;
        }

        if (needRestoreLocalAudio) {
            AVChatManager.getInstance().muteLocalAudio(false);
            needRestoreLocalAudio = false;
        }

    }

    /**
     * 关闭视频和语音发送.
     */
    public void pauseVideo() {
        AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "关闭视频和语音发送");
        if (!AVChatManager.getInstance().isLocalVideoMuted()) {
            AVChatManager.getInstance().muteLocalVideo(true);
            needRestoreLocalVideo = true;
        }

        if (!AVChatManager.getInstance().isLocalAudioMuted()) {
            AVChatManager.getInstance().muteLocalAudio(true);
            needRestoreLocalAudio = true;
        }
    }

    /**
     * *************************** 拨打和接听 ****************************
     */

    public void doCalling(String account, final AVChatType avChatType, final AVChatControllerCallback<AVChatData> callback) {

        AVChatManager.getInstance().enableRtc(AVPrivatizationConfig.getServerAddresses(context));
        AVChatManager.getInstance().setParameters(avChatConfigs.getAvChatParameters());
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_VIDEO_FRAME_FILTER, true);
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_SERVER_AUDIO_RECORD, true);
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_SERVER_VIDEO_RECORD, true);

        if (mVideoCapturer == null) {
            mVideoCapturer = AVChatVideoCapturerFactory.createCameraCapturer(true);
            AVChatManager.getInstance().setupVideoCapturer(mVideoCapturer);
        }

        if (avChatType == AVChatType.VIDEO) {
            AVChatManager.getInstance().enableVideo();
            AVChatManager.getInstance().startVideoPreview();
        }

        AVChatNotifyOption notifyOption = new AVChatNotifyOption();
        notifyOption.extendMessage = "extra_data";
        // 默认forceKeepCalling为true，开发者如果不需要离线持续呼叫功能可以将forceKeepCalling设为false
        // notifyOption.forceKeepCalling = false;
        AVChatManager.getInstance().call2(account, avChatType, notifyOption, new AVChatCallback<AVChatData>() {
            @Override
            public void onSuccess(AVChatData data) {
                avChatData = data;
                callback.onSuccess(data);
            }

            @Override
            public void onFailed(int code) {
                LogUtil.d(TAG, "avChat call failed code->" + code);

                if (code == ResponseCode.RES_FORBIDDEN) {
                    ToastUtil.toastShort(context, R.string.im_avchat_no_permission);
                    AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onFailed  暂无权限，请开通音视频服务 code:" + code);
                } else {
                    ToastUtil.toastShort(context, R.string.im_avchat_call_failed);
                    AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onFailed  发起通话失败 code:" + code);
                }
                closeRtc(avChatType == AVChatType.VIDEO ? CallStateEnum.VIDEO : CallStateEnum.AUDIO);
                callback.onFailed(code, "");
            }

            @Override
            public void onException(Throwable exception) {
                LogUtil.d(TAG, "avChat call onException->" + exception);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onException  avChat call onException->" + exception);

                closeRtc(avChatType == AVChatType.VIDEO ? CallStateEnum.VIDEO : CallStateEnum.AUDIO);
                callback.onFailed(-1, exception.toString());
            }
        });
    }

    public void receive(final AVChatType avChatType, final AVChatControllerCallback<Void> callback) {

        AVChatManager.getInstance().enableRtc(AVPrivatizationConfig.getServerAddresses(context));
        AVChatManager.getInstance().setParameters(avChatConfigs.getAvChatParameters());
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_VIDEO_FRAME_FILTER, true);
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_SERVER_AUDIO_RECORD, true);
        AVChatManager.getInstance().setParameter(AVChatParameters.KEY_SERVER_VIDEO_RECORD, true);

        if (mVideoCapturer == null) {
            mVideoCapturer = AVChatVideoCapturerFactory.createCameraCapturer(true);
            AVChatManager.getInstance().setupVideoCapturer(mVideoCapturer);
        }
        if (avChatType == AVChatType.VIDEO) {
            AVChatManager.getInstance().enableVideo();
            AVChatManager.getInstance().startVideoPreview();
        }

        AVChatManager.getInstance().accept2(avChatData.getChatId(), new AVChatCallback<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                LogUtil.i(TAG, "accept success");

                isCallEstablish.set(true);

                callback.onSuccess(aVoid);
            }

            @Override
            public void onFailed(int code) {
                if (code == -1) {
                    ToastUtil.toastShort(context, "本地音视频启动失败");
                    AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onFailed  本地音视频启动失败  code:" + code);

                } else {
                    ToastUtil.toastShort(context, "建立连接失败");
                    AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onFailed  建立连接失败 code:" + code);

                }
                LogUtil.e(TAG, "accept onFailed->" + code);
                handleAcceptFailed(avChatType == AVChatType.VIDEO ?
                        CallStateEnum.VIDEO_CONNECTING : CallStateEnum.AUDIO);
                callback.onFailed(code, "");
            }

            @Override
            public void onException(Throwable exception) {
                LogUtil.d(TAG, "accept exception->" + exception);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "onException  accept exception->" + exception);

                handleAcceptFailed(avChatType == AVChatType.VIDEO ?
                        CallStateEnum.VIDEO_CONNECTING : CallStateEnum.AUDIO);
                callback.onFailed(-1, exception.toString());
            }
        });
        AVChatSoundPlayer.instance().stop();
    }

    public void toggleMute() {
        if (!AVChatManager.getInstance().isLocalAudioMuted()) { // isMute是否处于静音状态
            // 关闭音频
            AVChatManager.getInstance().muteLocalAudio(true);
            AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "toggleMute  关闭音频");

        } else {
            // 打开音频
            AVChatManager.getInstance().muteLocalAudio(false);
            AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "toggleMute  打开音频");

        }
    }

    /**
     * ********************* 音视频切换 ***********************
     */

    // 发送视频切换为音频命令
    public void switchVideoToAudio(final AVSwitchListener avSwitchListener) {
        AVChatManager.getInstance().sendControlCommand(avChatData.getChatId(), AVChatControlCommand.SWITCH_VIDEO_TO_AUDIO, new AVChatCallback<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                LogUtil.d(TAG, "videoSwitchAudio onSuccess");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送视频切换为音频命令  onSuccess");

                //关闭视频
                AVChatManager.getInstance().stopVideoPreview();
                AVChatManager.getInstance().disableVideo();

                // 界面布局切换。
                avSwitchListener.onVideoToAudio();
            }

            @Override
            public void onFailed(int code) {
                LogUtil.d(TAG, "videoSwitchAudio onFailed");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送视频切换为音频命令  onFailed  code:" + code);

            }

            @Override
            public void onException(Throwable exception) {
                LogUtil.d(TAG, "videoSwitchAudio onException");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送视频切换为音频命令  onException  exception:" + exception);

            }
        });
    }

    // 发送音频切换为视频命令
    public void switchAudioToVideo(final AVSwitchListener avSwitchListener) {
        AVChatManager.getInstance().sendControlCommand(avChatData.getChatId(), AVChatControlCommand.SWITCH_AUDIO_TO_VIDEO, new AVChatCallback<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                LogUtil.d(TAG, "requestSwitchToVideo onSuccess");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送音频切换为视频命令  onSuccess");

                avSwitchListener.onAudioToVideo();
            }

            @Override
            public void onFailed(int code) {
                LogUtil.d(TAG, "requestSwitchToVideo onFailed" + code);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送音频切换为视频命令  onFailed:" + code);

            }

            @Override
            public void onException(Throwable exception) {
                LogUtil.d(TAG, "requestSwitchToVideo onException" + exception);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送音频切换为视频命令  onException:" + exception);

            }
        });
    }

    // 发送同意从音频切换为视频的命令
    public void receiveAudioToVideo(final AVSwitchListener avSwitchListener) {
        AVChatManager.getInstance().sendControlCommand(avChatData.getChatId(), AVChatControlCommand.SWITCH_AUDIO_TO_VIDEO_AGREE, new AVChatCallback<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                LogUtil.d(TAG, "receiveAudioToVideo onSuccess");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送同意从音频切换为视频的命令  onSuccess");

                avSwitchListener.onReceiveAudioToVideoAgree();
            }

            @Override
            public void onFailed(int code) {
                LogUtil.d(TAG, "receiveAudioToVideo onFailed");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN,
                        "switchVideoToAudio  发送同意从音频切换为视频的命令  onFailed:" + code);

            }

            @Override
            public void onException(Throwable exception) {
                LogUtil.d(TAG, "receiveAudioToVideo onException");
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "switchVideoToAudio  发送同意从音频切换为视频的命令  exception:" + exception);

            }
        });
    }


    /**
     * ********************* 其他设置 **************************
     */

    // 录制暂停和开始
    public void toggleRecord(int type, final String receiverId, final RecordCallback callback) {
        if (isRecording) {
            //停止录制
            isRecording = false;
            callback.onRecordUpdate(isRecording);
            if (recordList.size() == 3) {
                if (recordList.get(0).second) {
                    AVChatManager.getInstance().stopAudioRecording();
                }
                if (recordList.get(1).second) {
                    AVChatManager.getInstance().stopAVRecording(AVChatKit.getAccount());
                }
                if (recordList.get(2).second) {
                    AVChatManager.getInstance().stopAVRecording(receiverId);
                }
            }

        } else {
            //探测对话框
            final MultiSelectDialog selectDialog = new MultiSelectDialog(context);
            selectDialog.setTitle("选择录制内容");
            selectDialog.setMessage("录制的内容会被单独保存");
            selectDialog.setMessageTextColor(context.getResources().getColor(R.color.platform_color_grey_999999));
            selectDialog.addItem("语音对话", false);
            if (type == CallStateEnum.AUDIO.getValue()) {
                selectDialog.addItem("我的音频", false);
            } else {
                selectDialog.addItem("我的音视频", false);
            }
            if (type == CallStateEnum.AUDIO.getValue()) {
                selectDialog.addItem("对方音频", false);
            } else {
                selectDialog.addItem("对方音视频", false);
            }
            selectDialog.addPositiveButton("开始录制", MultiSelectDialog.NO_TEXT_COLOR, MultiSelectDialog.NO_TEXT_SIZE,
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            isRecording = true;
                            callback.onRecordUpdate(isRecording);
                            List<Pair<String, Boolean>> selectDialogList = selectDialog.getItemTextList();
                            if (selectDialogList.size() == 3) {
                                if (selectDialogList.get(0).second) {
                                    AVChatManager.getInstance().startAudioRecording();
                                }
                                if (selectDialogList.get(1).second) {
                                    AVChatManager.getInstance().startAVRecording(AVChatKit.getAccount());
                                }
                                if (selectDialogList.get(2).second) {
                                    AVChatManager.getInstance().startAVRecording(receiverId);
                                }
                            }
                            recordList.clear();
                            recordList.addAll(selectDialogList);
                            selectDialog.dismiss();
                        }
                    });
            selectDialog.addNegativeButton(context.getString(R.string.im_cancel), MultiSelectDialog.NO_TEXT_COLOR,
                    MultiSelectDialog.NO_TEXT_SIZE, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            selectDialog.dismiss();
                        }
                    });
            selectDialog.show();
        }
    }

    /**
     * 设置扬声器是否开启
     */
    public void toggleSpeaker() {
        AVChatManager.getInstance().setSpeaker(!AVChatManager.getInstance().speakerEnabled());
    }

    /**
     * 切换摄像头（主要用于前置和后置摄像头切换）
     */
    public void switchCamera() {
        mVideoCapturer.switchCamera();
    }

    /**
     * ********************** 挂断相关操作 **********************
     */

    public void hangUp(int type) {
        if (destroyRTC) {
            return;
        }
        if ((type == AVChatExitCode.HANGUP || type == AVChatExitCode.PEER_NO_RESPONSE
                || type == AVChatExitCode.CANCEL || type == AVChatExitCode.REJECT) && avChatData != null) {
            AVChatManager.getInstance().hangUp2(avChatData.getChatId(), new AVChatCallback<Void>() {
                @Override
                public void onSuccess(Void aVoid) {
                }

                @Override
                public void onFailed(int code) {
                    LogUtil.d(TAG, "hangup onFailed->" + code);
                }

                @Override
                public void onException(Throwable exception) {
                    LogUtil.d(TAG, "hangup onException->" + exception);
                }
            });
        }
        AVChatManager.getInstance().disableRtc();
        destroyRTC = true;
        AVChatSoundPlayer.instance().stop();
        showQuitToast(type);
    }

    /**收到挂断通知，自己的处理*/
    public void onHangUp(int exitCode) {
        if (destroyRTC) {
            return;
        }
        AVChatSoundPlayer.instance().stop();
        AVChatManager.getInstance().disableRtc();
        destroyRTC = true;
        showQuitToast(exitCode);
        ((Activity) context).finish();
    }

    /** 显示退出toast*/
    public void showQuitToast(int code) {
        switch (code) {
            // 网络切换
            case AVChatExitCode.NET_CHANGE:
                // 网络异常
            case AVChatExitCode.NET_ERROR:
                // 服务器返回数据错误
            case AVChatExitCode.CONFIG_ERROR:
                ToastUtil.toastShort(context, R.string.im_avchat_net_error_then_quit);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN,
                        "网络异常，通话结束   网络切换4 网络异常8 服务器返回数据错误10 code：" + code);
                break;
            case AVChatExitCode.REJECT:
                ToastUtil.toastShort(context, R.string.im_avchat_call_reject);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "被对方拒绝");
                break;
            case AVChatExitCode.PEER_HANGUP:
            case AVChatExitCode.HANGUP:
                if (isCallEstablish.get()) {
                    ToastUtil.toastShort(context, R.string.im_avchat_call_finish);
                    AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "通话结束");
                }
                break;
            case AVChatExitCode.PEER_BUSY:
                ToastUtil.toastShort(context, R.string.im_avchat_peer_busy);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "对方正在通话中，请稍后再拨。");
                break;
            case AVChatExitCode.PROTOCOL_INCOMPATIBLE_PEER_LOWER:
                ToastUtil.toastShort(context, R.string.im_avchat_peer_protocol_low_version);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "对方版本过低，请提示对方升");
                break;
            case AVChatExitCode.PROTOCOL_INCOMPATIBLE_SELF_LOWER:
                ToastUtil.toastShort(context, R.string.im_avchat_local_protocol_low_version);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "版本过低，请升级后使用");
                break;
            case AVChatExitCode.INVALIDE_CHANNELID:
                ToastUtil.toastShort(context, R.string.im_avchat_invalid_channel_id);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "对方已挂断");
                break;
            case AVChatExitCode.LOCAL_CALL_BUSY:
                ToastUtil.toastShort(context, R.string.im_avchat_local_call_busy);
                AliYunRichLogsHelper.Companion.getInstance().sendRichLog(AliYunLogConfig.YUNXIN, "本地通话中，无法进行通话。");
                break;
            default:
                break;
        }
    }

    private void closeRtc(CallStateEnum callingState) {
        if (destroyRTC) {
            return;
        }
        if (callingState == CallStateEnum.OUTGOING_VIDEO_CALLING || callingState == CallStateEnum.VIDEO) {
            AVChatManager.getInstance().stopVideoPreview();
            AVChatManager.getInstance().disableVideo();
        }
        AVChatManager.getInstance().disableRtc();
        destroyRTC = true;
        AVChatSoundPlayer.instance().stop();
    }

    private void handleAcceptFailed(CallStateEnum callingState) {
        if (callingState == CallStateEnum.VIDEO_CONNECTING) {
            AVChatManager.getInstance().stopVideoPreview();
            AVChatManager.getInstance().disableVideo();
        }
        hangUp(AVChatExitCode.CANCEL);
    }

    /**
     * ************************* 其他数据 ***********************
     */

    public long getTimeBase() {
        return timeBase;
    }

    public void setTimeBase(long timeBase) {
        this.timeBase = timeBase;
    }

    public AVChatData getAvChatData() {
        return avChatData;
    }

    public void setAvChatData(AVChatData avChatData) {
        this.avChatData = avChatData;
    }

    public boolean isRecording() {
        return isRecording;
    }

    public void setRecording(boolean recording) {
        isRecording = recording;
    }

}
