package com.mogo.cloud.live.manager;

import android.app.Application;
import android.media.AudioFormat;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;

import com.mogo.cloud.live.listener.ILiveRoomPersonListener;
import com.mogo.cloud.live.listener.ILivePushStatusListener;
import com.mogo.cloud.live.model.CommandModel;
import com.mogo.cloud.live.server.PushService;
import com.mogo.cloud.live.socket.SocketMsgUtils;
import com.mogo.cloud.live.socket.SocketRequestUtils;
import com.mogo.cloud.socket.IMogoCloudSocketOnMessageListener;
import com.mogo.cloud.socket.entity.MsgBody;

import java.util.ArrayList;

import im.zego.zegoexpress.constants.ZegoUpdateType;
import im.zego.zegoexpress.entity.ZegoUser;


/**
 * 直播流管理实现类
 *
 * @author donghongyu
 */
public class LiveStreamManagerImpl implements ILiveStreamManager, ILiveRoomPersonListener {
    private static final String TAG = "LiveStreamManagerImpl";

    private static volatile LiveStreamManagerImpl sInstance;

    private final Application mApplication;

    // 循环上报摄像头可直播状态间隔时间
    private static final int PUSH_CAM_TIME = 10 * 1000;
    // 检测房间在线人数，<=1代表无人观看，即可以关闭推流，1个人代表自己
    private static final int PUSH_CHECK_TIME = 120 * 1000;
    private static volatile int sCam1LiveStatus = 0, sCam2LiveStatus = 0;
    private static volatile int sCam1AvailableStatus = 0, sCam2AvailableStatus = 0;
    private static final int PUSH_START = 0;  // 开始
    private static final int PUSH_STOP = 1;   // 结束
    private static final int PUSH_FORCED_STOP = 2;   // 强制结束直播，不考虑是否有观众
    private static final String C1 = "C_1";   //前置摄像头
    private static final String C2 = "C_2";   //后置摄像头
    private Handler mHandlerPushCameraStatus;                 // 循环上报摄像头状态
    private Handler mHandlerCheckOnlineNum;                 //  检测在线观看人数
    private final SocketMsgUtils mSocketMsgUtils; // Socket 长链接
    private MoGoLiveManager mMoGoLiveManager;    // 自研直播SDK
    private CameraStatusManager cameraStatusManager;

    public static LiveStreamManagerImpl getInstance(Application application, String devicesId, boolean isExpressEngine) {
        if (sInstance == null) {
            synchronized (LiveStreamManagerImpl.class) {
                if (sInstance == null) {
                    sInstance = new LiveStreamManagerImpl(application, devicesId, isExpressEngine);
                }
            }
        }

        return sInstance;
    }


    private LiveStreamManagerImpl(Application application, String devicesId, boolean isExpressEngine) {
        mApplication = application;
        mHandlerPushCameraStatus = new Handler();
        mHandlerCheckOnlineNum = new Handler();
        cameraStatusManager = CameraStatusManager.getInstance();
        // 初始化直播推流
        initMoGoLiveManager(devicesId, isExpressEngine);
        // 初始化Socket长连接通道
        mSocketMsgUtils = SocketMsgUtils.getInstance(mApplication,
                new IMogoCloudSocketOnMessageListener<CommandModel>() {

                    @Override
                    public Class<CommandModel> target(int msgType) {
                        return CommandModel.class;
                    }

                    @Override
                    public void onMsgReceived(int msgType, CommandModel obj) {
                        Log.i(TAG, "onMsgReceived: obj=" + obj + "   systemClock :" + SystemClock.elapsedRealtime() + "  SystemTime : " + System.currentTimeMillis());
                        livePushHandler(obj.getType(), obj.getVideoChannel());
                    }
                });
        // 是自定义推流才开启上报摄像头状态
        if (isExpressEngine) {
            // 初始化查询摄像头状态
            restartCamStatusLoop();
        }
        // 开启房间人数检测
        restartCheckOnlineNumLoop();
        // 注册监听
        MoGoLiveManager.addLiveRoomPersonListener(this);
    }

    /**
     * 初始化直播引擎
     *
     * @param devicesId       设备ID
     * @param isExpressEngine 是否自定义采集
     */
    private void initMoGoLiveManager(String devicesId, boolean isExpressEngine) {
        // 初始化配置文件
        MoGoLivePushConfig mLivePushConfig = MoGoLivePushConfig.getInstance();
        mLivePushConfig.setWidth(1280);
        mLivePushConfig.setHeight(720);
        mLivePushConfig.setVideoBitrate(6000);
        mLivePushConfig.setVideoFPS(30);
        mLivePushConfig.setAudioChannels(2);
        mLivePushConfig.setAudioSampleRate(44100);
        mLivePushConfig.setAudioFormat(AudioFormat.ENCODING_PCM_16BIT);
        mLivePushConfig.setMute(true);
        mLivePushConfig.setDevicesId(devicesId);
        mLivePushConfig.setExpressEngine(isExpressEngine);
        // 初始化直播
        mMoGoLiveManager = MoGoLiveManager.getInstance().init(mApplication, mLivePushConfig);
    }

    public MoGoLiveManager getMoGoLiveManager() {
        return mMoGoLiveManager;
    }

    /**
     * 获取前置摄像头直播状态
     */
    @Override
    public int getLiveStatus() {
        return sCam1LiveStatus;
    }

    @Override
    public void startLiveStream() {
        Log.i(TAG, "startLiveStream");
        PushService.startService(mApplication, PushService.ACTION_START_RTMP_PUSH);
    }

    @Override
    public void stopLiveStream() {
        Log.i(TAG, "stopLiveStream");
        PushService.startService(mApplication, PushService.ACTION_STOP_RTMP_PUSH);
    }

    @Override
    public void uploadCamStatus(int frontStatus, int backStatus) {
        Log.i(TAG, "上传摄像头状态 frontStatus is:" + frontStatus + " backStatus is:" + backStatus);
        sCam1AvailableStatus = frontStatus;
        sCam2AvailableStatus = backStatus;
        MsgBody msgBody = new MsgBody();
        msgBody.msgType(196614);
        msgBody.content(SocketRequestUtils.buildDeviceData(frontStatus, backStatus));

        mSocketMsgUtils.uploadCamInfo(msgBody);

        cameraStatusManager.reportCameraStatus(frontStatus, backStatus);
    }

    @Override
    public void notifyYUVData(byte[] data, int width, int height, int type) {
        CameraFrameManager.getInstance().notifyYUVData(data, width, height, type);
    }

    @Override
    public void setLivePushStatusChangeCallback(ILivePushStatusListener liveStatusListener) {
        if (mMoGoLiveManager != null) {
            mMoGoLiveManager.addLivePushStatusListener(liveStatusListener);
        }
    }

    @Override
    public void release() {
        try {
            mHandlerPushCameraStatus.removeCallbacks(mCamStatusRun);
            mHandlerPushCameraStatus = null;
            mHandlerCheckOnlineNum.removeCallbacks(mOnlineNumRun);
            mHandlerCheckOnlineNum = null;
            mSocketMsgUtils.release();
            sCam1LiveStatus = 0;
            sCam2LiveStatus = 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开启摄像头状态循环检测
     */
    private void restartCamStatusLoop() {
        Log.i(TAG, "开启摄像头状态循环检测");
        if (mHandlerPushCameraStatus != null) {
            mHandlerPushCameraStatus.removeCallbacks(mCamStatusRun);
            mHandlerPushCameraStatus.postDelayed(mCamStatusRun, PUSH_CAM_TIME);
        }
    }

    /**
     * 开启房间人数检测
     */
    private void restartCheckOnlineNumLoop() {
        Log.i(TAG, "开启房间人数检测");
        if (mHandlerCheckOnlineNum != null) {
            mHandlerCheckOnlineNum.removeCallbacks(mOnlineNumRun);
            mHandlerCheckOnlineNum.postDelayed(mOnlineNumRun, PUSH_CHECK_TIME);
        }
    }

    /**
     * 循环同步摄像头状态
     */
    private final Runnable mCamStatusRun = () -> {
        Log.i(TAG, "循环同步摄像头状态");
        uploadCamStatus(sCam1AvailableStatus, sCam2AvailableStatus);
        restartCamStatusLoop();
    };

    /**
     * 房间在线人数检测，1=只有自己需要关闭推流，>1 代表有观众在观看需要开启推流
     */
    private final Runnable mOnlineNumRun = () -> {
        // 判断当前观众的个数，如果没人观看了的情况则停止直播
        Log.i(TAG, "直播状态为：" + mMoGoLiveManager.getLiveStatusModel().isPushing() +
                "  观众人数：" + mMoGoLiveManager.getLiveStatusModel().getOnlineNumber());

        if (mMoGoLiveManager.getLiveStatusModel().isPushing() &&
                mMoGoLiveManager.getLiveStatusModel().getOnlineNumber() <= 1) {
            livePushHandler(PUSH_STOP, C1);
        }
        restartCheckOnlineNumLoop();
    };

    /**
     * 接收到长连接指令
     *
     * @param videoChannel 指令数据
     */
    public void livePushHandler(int status, String videoChannel) {
        try {
            // 前置摄像头
            if (C1.equals(videoChannel)) {
                // 停止直播
                if (status == PUSH_STOP) {
                    stopLiveStream();
                    // 释放资源
                    CameraFrameManager.getInstance().release();
                }
                // 开始直播
                else if (status == PUSH_START) {
                    startLiveStream();
                }
                // 强制关闭直播
                else if (status == PUSH_FORCED_STOP) {
                    PushService.startService(mApplication, PushService.ACTION_FORCED_STOP_RTMP_PUSH);
                }
                // 记录直播状态
                sCam1LiveStatus = status;
            } else {
                Log.e(TAG, "目前只支持前置行车记录仪");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRoomOnlineUserCountUpdate(int count) {

    }

    @Override
    public void onRoomUserUpdate(ZegoUpdateType updateType, ArrayList<ZegoUser> userList) {
        // 判断直播中，观看用户等于1，关闭直播
        if (mMoGoLiveManager.getLiveStatusModel().isPushing() &&
                mMoGoLiveManager.getLiveStatusModel().getOnlineNumber() <= 1) {
            livePushHandler(PUSH_STOP, C1);
        }
        // 判断没有直播，并且观看用户大于2，开启直播
        if (!mMoGoLiveManager.getLiveStatusModel().isPushing() &&
                mMoGoLiveManager.getLiveStatusModel().getOnlineNumber() >= 2) {
            livePushHandler(PUSH_START, C1);
        }
    }
}
