package com.yidianling.avchatkit.receiver;

import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.avchat.AVChatCallback;
import com.netease.nimlib.sdk.avchat.AVChatManager;
import com.yidianling.avchatkit.common.log.LogUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by huangjun on 2015/5/13.
 */
public class PhoneCallStateObserver {

    public enum PhoneCallStateEnum {
        IDLE,           // 空闲
        INCOMING_CALL,  // 有来电
        DIALING_OUT,    // 呼出电话已经接通
        DIALING_IN      // 来电已接通
    }

    private final String TAG = "PhoneCallStateObserver";

    private int phoneState = TelephonyManager.CALL_STATE_IDLE;
    private PhoneCallStateEnum stateEnum = PhoneCallStateObserver.PhoneCallStateEnum.IDLE;

    private List<Observer<Integer>> autoHangUpObservers = new ArrayList<>(1); // 与本地电话互斥的挂断监听

    private static class InstanceHolder {
        public final static PhoneCallStateObserver instance = new PhoneCallStateObserver();
    }

    private PhoneCallStateObserver() {

    }

    public static PhoneCallStateObserver getInstance() {
        return InstanceHolder.instance;
    }

    public void onCallStateChanged(String state) {
        Log.i(TAG, "onCallStateChanged, now state =" + state);

        stateEnum = PhoneCallStateEnum.IDLE;
        if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
            phoneState = TelephonyManager.CALL_STATE_IDLE;
            stateEnum = PhoneCallStateEnum.IDLE;
        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
            phoneState = TelephonyManager.CALL_STATE_RINGING;
            stateEnum = PhoneCallStateEnum.INCOMING_CALL;
        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state)) {
            int lastPhoneState = phoneState;
            phoneState = TelephonyManager.CALL_STATE_OFFHOOK;
            if (lastPhoneState == TelephonyManager.CALL_STATE_IDLE) {
                stateEnum = PhoneCallStateEnum.DIALING_OUT;
            } else if (lastPhoneState == TelephonyManager.CALL_STATE_RINGING) {
                stateEnum = PhoneCallStateEnum.DIALING_IN;
            }
        }

        handleLocalCall();
    }

    /**
     * 处理本地电话与网络通话的互斥
     */
    public void handleLocalCall() {
        LogUtil.i(TAG, "notify phone state changed, state=" + stateEnum.name());

        if (stateEnum != PhoneCallStateEnum.IDLE) {
            AVChatManager.getInstance().hangUp2(AVChatManager.getInstance().getCurrentChatId(), new HandleLocalCallCallback(1));
        }
    }

    public PhoneCallStateEnum getPhoneCallState() {
        return stateEnum;
    }

    private class HandleLocalCallCallback implements AVChatCallback<Void> {
        private int reason;
        private String log;

        public HandleLocalCallCallback(int reason) {
            this.reason = reason;
            this.log = "handle local call";
        }

        @Override
        public void onSuccess(Void param) {
            notifyObservers(autoHangUpObservers, reason);
        }

        @Override
        public void onFailed(int code) {
            notifyObservers(autoHangUpObservers, -1 * reason);
        }

        @Override
        public void onException(Throwable exception) {
            notifyObservers(autoHangUpObservers, 0);

            if (!TextUtils.isEmpty(log)) {
                LogUtil.i(TAG, log + " throws exception, e=" + exception.getMessage());
            }
        }
    }

    private <T> void notifyObservers(List<Observer<T>> observers, T result) {
        if (observers == null || observers.isEmpty()) {
            return;
        }

        // 创建副本,为了使得回调到app后,app如果立即注销观察者,会造成List异常。
        List<Observer<T>> copy = new ArrayList<>(observers.size());
        copy.addAll(observers);

        for (Observer<T> o : copy) {
            o.onEvent(result);
        }
    }

    private <T> void registerObservers(List<Observer<T>> observers, final Observer<T> observer, boolean register) {
        if (observers == null || observer == null) {
            return;
        }

        if (register) {
            observers.add(observer);
        } else {
            observers.remove(observer);
        }
    }

    /**
     * 监听网络通话发起,接听或正在进行时有本地来电的通知
     * 网络通话发起或者正在接通时,需要监听是否有本地来电(用户接通本地来电)。
     * 若有本地来电,目前Demo中示例代码的处理是网络通话自动拒绝或者挂断,开发者可以自行灵活处理。
     */
    public void observeAutoHangUpForLocalPhone(Observer<Integer> observer, boolean register) {
        LogUtil.i(TAG, "observeAutoHangUpForLocalPhone->" + observer + "#" + register);
        registerObservers(this.autoHangUpObservers, observer, register);
    }
}