package cn.pluss.platform.util;

import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 极光推送
 */
@Slf4j
public class JGPushUtil implements IPush {

    private static IPush instance;

    private JGPushUtil() {
    }

    public static IPush getInstance() {
        if (instance == null) {
            instance = new JGPushUtil();
        }

        return instance;
    }

    private final static String APP_KEY = "46a8063491a3a1e89ec9254f";

    private final static String MASTER_SECRET = "ee279316fb21f2ec65390768";

    private static JPushClient jpushClient;

    public static JPushClient getJPushClient() {
        if (jpushClient == null) {
            jpushClient = new JPushClient(MASTER_SECRET, APP_KEY);
        }

        return jpushClient;
    }

    @Override
    public void sendAndroidByAlias(List<String> alias, String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.android())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.alias(alias))
                //jpush的通知，android的由jpush直接下发，iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        //指定当前推送的android通知
                        .addPlatformNotification(getAndroidNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }

    @Override
    public void sendIOSByAlias(List<String> alias, String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.ios())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.alias(alias))
                // iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        //指定当前推送的android通知
                        .addPlatformNotification(getIOSNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }

    @Override
    public void sendAllPlatByAlias(List<String> alias, String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.android_ios())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.alias(alias))
                .setNotification(Notification.newBuilder()
                        .addPlatformNotification(getIOSNotification(notificationTitle, msgContent, extrasParam))
                        .addPlatformNotification(getAndroidNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }

    @Override
    public void sendIOSAll(String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.ios())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.all())
                // iOS的由apns服务器下发，Winphone的由mpns下发
                .setNotification(Notification.newBuilder()
                        .addPlatformNotification(getIOSNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }

    @Override
    public void sendAndroidAll(String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.android())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.all())
                .setNotification(Notification.newBuilder()
                        .addPlatformNotification(getAndroidNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }

    @Override
    public void sendAllPlatAll(String notificationTitle, String msgContent, String extrasParam) {
        PushPayload pushPayload = getPayLoadBuilder(notificationTitle, msgContent, extrasParam)
                .setPlatform(Platform.android_ios())
                //指定推送的接收对象，all代表所有人，也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
                .setAudience(Audience.all())
                .setNotification(Notification.newBuilder()
                        .addPlatformNotification(getIOSNotification(notificationTitle, msgContent, extrasParam))
                        .addPlatformNotification(getAndroidNotification(notificationTitle, msgContent, extrasParam))
                        .build())
                .build();

        sendAndResultHandle(pushPayload);
    }


    private AndroidNotification getAndroidNotification(String notificationTitle, String msgContent, String extrasParam) {
        return AndroidNotification.newBuilder()
                .setAlert(msgContent)
                .setTitle(notificationTitle)
                // Notification.DEFAULT_ALL = -1
                // Notification.DEFAULT_VIBRATE = 2
                // Notification.DEFAULT_LIGHTS = 4
                .setAlertType(-1)
                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                .addExtra("url", extrasParam)
                .build();
    }

    /**
     * 获取iOS的通知构造体
     *
     * @param notificationTitle 标题
     * @param msgContent        内容
     * @param extrasParam       附加参数
     * @return
     */
    private IosNotification getIOSNotification(String notificationTitle, String msgContent, String extrasParam) {
        return IosNotification.newBuilder()
                //传一个IosAlert对象，指定apns title、title、subtitle等
                .setAlert(msgContent)
                .setMutableContent(true)
                //直接传alert
                //此项是指定此推送的badge自动加1
                .incrBadge(1)
                //此字段的值default表示系统默认声音；传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒，
                // 如果系统没有此音频则以系统默认声音提醒；此字段如果传空字符串，iOS9及以上的系统是无声音提醒，以下的系统是默认声音
                .setSound("sound.caf")
                //此字段为透传字段，不会显示在通知栏。用户可以通过此字段来做一些定制需求，如特定的key传要指定跳转的页面（value）
                .addExtra("url", extrasParam)
                //此项说明此推送是一个background推送，想了解background看：http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
                //取消此注释，消息推送时ios将无法在锁屏情况接收
                // .setContentAvailable(true)
                .build();
    }

    private PushPayload.Builder getPayLoadBuilder(String notificationTitle, String msgContent, String extrasParam) {
        return PushPayload.newBuilder()
                //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息，
                // sdk默认不做任何处理，不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
                .setMessage(Message.newBuilder()
                        .setMsgContent(msgContent)
                        .setTitle(notificationTitle)
                        .addExtra("5", extrasParam)
                        .build())
                .setOptions(Options.newBuilder()
                        //此字段的值是用来指定本推送要推送的apns环境，false表示开发，true表示生产；对android和自定义消息无意义
                        .setApnsProduction(MobPushUtil.PROD == 1)
                        //此字段是给开发者自己给推送编号，方便推送者分辨推送记录
                        .setSendno(1)
                        .build());
    }

    /**
     * 发送推送并对结果进行处理
     * @param pushPayload
     */
    void sendAndResultHandle(PushPayload pushPayload) {
        try {
            PushResult pushResult = getJPushClient().sendPush(pushPayload);
//            System.out.println("[极光推送]    PushResult result is " + pushResult);
            log.info("[极光推送]    PushResult result is " + pushResult);
        } catch (APIConnectionException e) {
            log.error("[极光推送]    Connection error. Should retry later. {}", e.toString());
        } catch (APIRequestException e) {
            System.out.println("[极光推送] " + e.getErrorMessage());
//            log.error("[极光推送]Error response from JPush server. Should review and fix it. ", e);
            log.info("[极光推送]HTTP Status: " + e.getStatus());
            log.info("[极光推送]Error Code: " + e.getErrorCode());
            log.info("[极光推送]Error Message: " + e.getErrorMessage());
        }
    }
}
