package com.baidu.ai.sample;

import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;

import com.baidu.ai.sample.data.AIClientData;
import com.baidu.ai.sample.data.VideoViewDisplay;
import com.baidu.ai.sample.util.AudioDevice;
import com.baidu.ai.sample.util.JavaTypesHelper;
import com.baidu.ai.sample.util.Utils;
import com.baidu.ai.sample.util.ZMediaPlayer;
import com.baidu.rtc.RTCVideoView;
import com.baidu.rtc.agent.AIAgentEngine;
import com.baidu.rtc.agent.AIAgentEngineCallback;
import com.baidu.rtc.agent.Constants;
import com.baidu.rtc.audio.AudioKeepService;
import com.webrtc.Logging;
import com.webrtc.RendererCommon;

import org.json.JSONArray;
import org.json.JSONObject;

public class AIController extends AIAgentEngineCallback {
    private static final String TAG = "AIController";
    private AIAgentEngine.AIAgentEngineParams mAiAgentParams;
    private AIAgentEngine mAiAgent;
    private AIClientData mClientData;
    private Activity mActivity;

    private AIAgentEngineCallback mCallback;
    private ZMediaPlayer mMediaPlayer;

    private AudioDevice mAudioDevice;

    private RTCVideoView mLocalVideoView;
    private VideoViewDisplay mCRDisplay;
    private VideoViewDisplay mDHDisplay;

    public void onCreate(Activity activity, AIClientData data, AIAgentEngineCallback callback) {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        mActivity = activity;
        mClientData = data;
        mCallback = callback;

//        mAgentAnimationView = activity.findViewById(R.id.agent_loading);
//        mUserAnimationView = activity.findViewById(R.id.user_loading);
        if (mClientData == null) {
            Log.e(TAG, "error InitRTCRoom mClientData is null !!");
            return;
        }
        mClientData.checkData(activity);
    }

    public void initRtcRoom() {
        Logging.w(TAG, "mClientData:" + mClientData.dumpString());

        mAiAgentParams = new AIAgentEngine.AIAgentEngineParams();
        mAiAgentParams.appId = mClientData.mAppId;
        mAiAgentParams.context = mClientData.mContext;
        /** license 信息*/
//        mAiAgentParams.licenseKey = "xxx";
        /** license 信息*/
//        mAiAgentParams.userId = "xxx";

        if (!TextUtils.isEmpty(mClientData.mLicenseKey)) {
            mAiAgentParams.licenseKey = mClientData.mLicenseKey;
        }
        if (!TextUtils.isEmpty(mClientData.mUserID)) {
            mAiAgentParams.userId = mClientData.mUserID;
        }

        /** 调试日志 */
        mAiAgentParams.verbose = true;
//        mAiAgentParams.enableLogWriteToDisk = true;
//        mAiAgentParams.enableLogCallback = true;
        /** 更改音频编码器 */
        if (!TextUtils.isEmpty(mClientData.mAudioCodec)) {
            mAiAgentParams.audioCodec = mClientData.mAudioCodec;
        }
//        /** 外部音频采集 */
//        mAiAgentParams.enableExternalAudioInput = true;
//        /** 外部音频渲染 */
//        mAiAgentParams.enableExternalAudioOutput = true;

        // 初始化
        mAiAgent = AIAgentEngine.init(mActivity, mAiAgentParams);
        mAiAgent.setCallback(this);
        mAudioDevice = new AudioDevice(mActivity.getApplicationContext(), mAiAgent);
        mLocalVideoView = new RTCVideoView(mActivity.getApplicationContext(), RTCVideoView.ViewType.TEXTURE_VIEW);
        mLocalVideoView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        if (mAiAgentParams.enableExternalAudioOutput) {
            mAudioDevice.startOutput();
        }
    }
    public void muteCamera(boolean mute) {
        if (mute) {
            mAiAgent.stopCameraPreview();
        } else {
            mAiAgent.startCameraPreview();
        }
    }

    public void switchCamera() {
        mAiAgent.switchCamera();
    }

    public void mutePlayback(boolean isMute) {
        mAiAgent.mutePlayback(isMute);
    }

    public RTCVideoView getLocalVideoView() {
        return mLocalVideoView;
    }

    public void callAgent() {
        Log.i(TAG, "callAgent");
        mAiAgent.call(mClientData.mTokenStr, JavaTypesHelper.toLong(mClientData.mInstanceId, 1));
        mAiAgent.switchToSpeaker(true);
        if (mCRDisplay != null) {
            mAiAgent.setCloudRenderDisplay(mCRDisplay.mGroup, mCRDisplay.mParams, mCRDisplay.mType);
        } else if (mDHDisplay != null) {
            mAiAgent.setDigitalDisplay(mDHDisplay.mGroup, mDHDisplay.mParams, mDHDisplay.mType);
        }
        if (mLocalVideoView != null) {
            mAiAgent.setLocalVideoView(mLocalVideoView);
        }
        if (!mAiAgentParams.enableExternalAudioInput) {
            startRoomKeepLifeService();
        }
    }

    public void sendText(String text) {
        Log.i(TAG, "sendText:" + text);
        if (text.startsWith("[E]:[CMD]:")) {
            String cmd = text.substring("[E]:[CMD]:".length());
            mAiAgent.sendCommand(cmd);
        } else {
            mAiAgent.sendTextToAIAgent(text);
        }
    }
    public void interrupt() {
        if (mAiAgent != null) {
            mAiAgent.interrupt();
        }
        audioPlayStop();
    }

    public void sendTextToTTS(String msg) {
        if (mAiAgent != null) {
            mAiAgent.sendTextToTTS(msg);
        }
    }

    public void muteMic(boolean isMute) {
        if (mAiAgent != null) {
            mAiAgent.muteMic(isMute);
        }
    }

    public void upload(int scenario, String path, int expire) {
        if (mAiAgent != null) {
            // 过期时间 单位秒, 最大值默认180秒, 最小值0 (关闭缓存);
            mAiAgent.uploadFile(scenario, path, expire);
        }
    }
    public void updateSystemPrompt(int modelType, String prompt) {
        if (mAiAgent != null) {
            mAiAgent.updateSystemPrompt(modelType, prompt);
        }
    }

    public void setCloudRenderDisplay(ViewGroup group, ViewGroup.LayoutParams params, RTCVideoView.ScalingType type) {
        if (group == null || params == null) {
            Log.i(TAG, "setCloudRenderDisplay invalid params: " + group + ", " + params);
        }
        mCRDisplay = new VideoViewDisplay(group, params, type, VideoViewDisplay.CLOUD_RENDER);
    }

    public void setDigitalDisplay(ViewGroup group, ViewGroup.LayoutParams params, RTCVideoView.ScalingType type) {
        if (group == null || params == null) {
            Log.i(TAG, "setDigitalDisplay invalid params: " + group + ", " + params);
        }
        mDHDisplay = new VideoViewDisplay(group, params, type, VideoViewDisplay.DIGITAL_HUMAN);
    }

    public void onResume() {
        hideBottomUIMenu();
    }

    private void startRoomKeepLifeService() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Intent serviceIntent = new Intent(mActivity, AudioKeepService.class);
            serviceIntent.putExtra("command", "start");
            ContextCompat.startForegroundService(mActivity, serviceIntent);
            Log.i(TAG, "startRoomKeepLifeService, start");
        } else {
            Log.i(TAG, "startRoomKeepLifeService no start, Build.VERSION.SDK_INT:" + Build.VERSION.SDK_INT);
        }
    }
    private void stopRoomKeepLifeService(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            Intent serviceIntent = new Intent(mActivity, AudioKeepService.class);
            serviceIntent.putExtra("command", "stop");
            ContextCompat.startForegroundService(mActivity, serviceIntent);
            Log.i(TAG, "stopRoomKeepLifeService, stop");
        } else {
            Log.i(TAG, "stopRoomKeepLifeService no stop, Build.VERSION.SDK_INT:" + Build.VERSION.SDK_INT);
        }
    }

    @Override
    public void onConnectionStateChange(int state) {
        Log.i(TAG, "onConnectionStateChanged, state:" + Utils.getStateString(state));
        if (state == Constants.ConnectionState.CONNECTION_STATE_DISCONNECTED) {
            Log.i(TAG, "Reconnecting.. CONNECTION_STATE_DISCONNECTED:");
        } else if (state == Constants.ConnectionState.CONNECTION_STATE_RECONNECTING) {
            Log.i(TAG, "Reconnecting..");
        }
    }

    @Override
    public void onCallStateChange(int state) {
        if (mCallback != null) {
            mCallback.onCallStateChange(state);
        }

        /** 检查是否开始推流 */
        if (state == Constants.CallState.ON_CALL_BEGIN) {
            if (mAiAgentParams.enableExternalAudioInput) {
               mAudioDevice.startInput();
            }
            if (!TextUtils.isEmpty(mClientData.mQueryEnhanceType)) {
                mAiAgent.updateEnhanceQuery(mClientData.mQueryEnhanceType, mClientData.mPreQuery,
                        mClientData.mPostQuery);
            }
            if (!TextUtils.isEmpty(mClientData.mHintHistory)) {
                try {
                    JSONObject root = new JSONObject(mClientData.mHintHistory);
                    String hintType = root.optString("hint_type", "");
                    String question = root.optString("question", "");
                    String answer = root.optString("answer", "");

                    if (TextUtils.isEmpty(hintType) || TextUtils.isEmpty(question) || TextUtils.isEmpty(answer)) {
                        return;
                    }
                    mAiAgent.updateHintHistory(hintType, question, answer);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public void onError(int error, String msg, Bundle bundle) {
        finishActivity();
        Log.e(TAG, "onError, code:" + error + ",msg:" + msg + ",bundle:" + bundle);
    }


    @Override
    public void onUserAsrSubtitle(String text, boolean isFinal, Constants.ASRExtInfo info) {
        Log.d(TAG, " onUserAsrSubtitle text " + text + " isFinal: " + isFinal);
        if (mCallback != null) {
            mCallback.onUserAsrSubtitle(text, isFinal, info);
        }
    }

    @Override
    public void onAIAgentSubtitle(String text, boolean isFinal) {
        Log.d(TAG, " onAIAgentSubtitle text " + text + " isFinal: " + isFinal);
        if (mCallback != null) {
            mCallback.onAIAgentSubtitle(text, isFinal);
        }
    }

    /**
     * 间隔100ms 回调一次
     * 智能体远端音频能量
     * */
    @Override
    public void onAIAgentAudioLevel(int level) {
        Log.i(TAG, "onAIAgentAudioLevel, level:" + level);
    }

    /**
     * 间隔100ms 回调一次
     * 用户本地音频能量回调
     * */
    @Override
    public void onUserAudioLevel(int level) {
        Log.i(TAG, "onUserAudioLevel, level:" + level);
    }

    /**
     * 智能体音频状态变化
     * @param newState  状态 #{@link com.baidu.rtc.agent.Constants.AIAgentAudioStateType }
     * */
    @Override
    public void onAIAgentAudioStateChange(int newState) {
        if (newState == Constants.AIAgentAudioStateType.STOPPED) {
            Log.i(TAG, "onAIAgentAudioStateChange, stopped");
            mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
//                    mAgentAnimationView.pauseAnimation();
                }
            });
        } else if (newState == Constants.AIAgentAudioStateType.SPEAKING) {
            Log.i(TAG, "onAIAgentAudioStateChange, speaking");
            mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
//                    mAgentAnimationView.playAnimation();
                }
            });
        }
    }

    /**
     * 本地音频状态变化
     * @param newState  状态 #{@link com.baidu.rtc.agent.Constants.UserAudioStateType }
     * */
    @Override
    public void onUserAudioStateChange(int newState) {
        if (newState == Constants.UserAudioStateType.STOPPED) {
            Log.i(TAG, "onUserAudioStateChange, stopped");

        } else if (newState == Constants.UserAudioStateType.SPEAKING) {
            Log.i(TAG, "onUserAudioStateChange, speaking");
        }
    }

    @Override
    public void onFunctionCall(String id, String funcCallName, String params) {
        Log.i(TAG, "onFunctionCall id:" + id + ", params:" + params);
        // TODO: 处理function-call, 然后调用 sendFunctionCallResult
        String functionName = processFunction(id, params);
        toast("functionCall");
        // run_ab_fenghuang_news 特殊处理，不在此处返回
        if (!TextUtils.equals(functionName, "run_ab_fenghuang_news")) {
            mAiAgent.sendFunctionCallResult(id, "finish function call!");
        }
    }

    @Override
    public void onUploadFileStatus(int code, String msg) {
        Log.d(TAG, "onUploadFileStatus, code:" + code + " ,msg:" + msg);
        if (mCallback != null) {
            mCallback.onUploadFileStatus(code, msg);
        }
    }

    @Override
    public void onLicenseStatus(int code) {
        Log.d(TAG, "onLicenseStatus, code:" + code);
        if (code == Constants.NO_ERROR) {
            toast("license check success");
        } else {
            toast("license check fail");
        }
    }

    @Override
    public void onAgentIntent(String type, Bundle bundle) {
        Log.d(TAG, "onAgentIntent, type:" + type + " ,bundle:" + bundle);
        if (TextUtils.equals(type, Constants.AgentIntentType.IMAGE_UPLOAD)) {
            toast("intent image");
            mCallback.onAgentIntent(type, bundle);
            return;
        }
        if (TextUtils.equals(type, Constants.AgentIntentType.AUDIO_PLAY)) {
            toast("intent audio");
            onAudioPlay(bundle);
            return;
        }
    }

    @Override
    public void onMediaGenerateStart(long taskId, String query) {
        Log.d(TAG, "onMediaGenerateStart, taskId:" + taskId + ", query:" + query);
        if (mCallback != null) {
            mCallback.onMediaGenerateStart(taskId, query);
        }
    }

    @Override
    public void onMediaGenerateCompleted(long task, int type, int error, ArrayList<Constants.MediaGenerateResult> resList,
                                         String msgRes) {
        Log.d(TAG, "onMediaGenerate, type:" + type + ",error:" + error + ",resList:" + resList);
        if (mCallback != null) {
            mCallback.onMediaGenerateCompleted(task, type, error, resList, msgRes);
        }
    }

    @Override
    public void onRecvTagMessage(String msg, boolean isFinal) {
        Log.i(TAG, "onRecvTagMessage, msg:" + msg + ",isFinal:" + isFinal);
        if (mCallback != null) {
            mCallback.onRecvTagMessage(msg, isFinal);
        }
    }

    /** 音频输出接口 */
    @Override
    public void onPlaybackAudioFrame(byte[] data, int sampleRate, int channelCount) {
        if (mAudioDevice != null) {
            mAudioDevice.renderAudioFrame(data, sampleRate, channelCount);
        }
    }

    private String processFunction(String id, String msg) {
        try {
            Log.i(TAG, "processFunction, msg:" + msg);
            JSONObject root = new JSONObject(msg);
            String content = root.optString("content", "");
            if (TextUtils.isEmpty(content)) {
                return "";
            }
            root = new JSONObject(content);
            String name = root.optString("function_name", "");
            if (TextUtils.equals(name, "play_control")) {

                JSONArray params = root.optJSONArray("parameter_list");
                for (int i = 0; i < params.length(); i++) {
                    JSONObject obj = params.getJSONObject(i);
                    String key = obj.optString("mode", "");
                    if (TextUtils.equals(key, "stop") || TextUtils.equals(key, "pause") ) {
                        Log.i(TAG, "processFunction, stop audio play");
                        audioPlayStop();
                        return name;
                    }
                }
                return name;
            }

            if (TextUtils.equals(name, "take_photo") || TextUtils.equals(name, "record_video")) {
                mCallback.onFunctionCall(id, name, "");
            } else if (TextUtils.equals(name, "run_ab_fenghuang_news")) {
                JSONArray params = root.optJSONArray("parameter_list");
                JSONObject obj = params.getJSONObject(0);
                String queryContent = obj.optString("content_name", "");
                mCallback.onFunctionCall(id, name, queryContent);
            }

            return name;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public void sendFunctionCallResult(String id, String result) {
        if (mAiAgent != null) {
            Log.i(TAG, "sendFunctionCallResult id:" + id + ", result:" + result);
            mAiAgent.sendFunctionCallResult(id, result);
        }
    }

    private void onAudioPlay(Bundle bundle) {
        String url = bundle.getString("url", "");
        if (TextUtils.isEmpty(url)) {
            Log.i(TAG, "onAudioPlay url is empty!");
            return;
        }

        try {
            if (mMediaPlayer == null) {
                mMediaPlayer = new ZMediaPlayer();
            }
            mMediaPlayer.play(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void audioPlayStop() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop2();
        }
    }
    private void toast(String msg) {
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }


    private void finishActivity() {
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mAiAgent.hangup();
                finish();
            }
        });
    }

    private void destroyAll() {
        if (mAiAgent != null) {
            mAiAgent.destroy();
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.destroy();
        }
        if (mAudioDevice != null) {
            mAudioDevice.destroy();
        }
        if (!mAiAgentParams.enableExternalAudioInput) {
            stopRoomKeepLifeService();
        }
        Log.i(TAG, "destroyAll done");
    }

    public void finish() {
        destroyAll();
        mActivity.finish();
    }

    public void onDestroy() {
        destroyAll();
        Log.i(TAG, "onDestroy done");
    }


    protected void hideBottomUIMenu() {
        if (mActivity == null) {
            return;
        }

        // full screen no bottomUI.
        if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
            View v = mActivity.getWindow().getDecorView();
            v.setSystemUiVisibility(View.GONE);
        } else if (Build.VERSION.SDK_INT >= 19) {
            // for new api versions.
            View decorView = mActivity.getWindow().getDecorView();
            int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
            decorView.setSystemUiVisibility(uiOptions);
        }
    }
}
