package cn.com.ty.lift.push.app;

import cn.com.ty.lift.common.utils.ValuePool;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.tencent.xinge.XingeApp;
import com.tencent.xinge.bean.*;
import com.tencent.xinge.push.app.PushAppRequest;
import com.tencent.xinge.push.app.PushAppResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;

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

/**
 * 腾讯信鸽推动 https://xg.qq.com/docs/server_api/v3/push_api_v3.html
 *
 * @author wcz
 * @since 2020/2/10
 */
@Slf4j
public class XingePush {
    private String appId     = "40d4e2e854433";
    private String secretKey = "fa99dc19157b00fc71cf8d7e840273a3";

    /**
     * 消息推送 >>>
     */
    private XingeApp xingeApp;

    /**
     * 默认配置创建xinge push
     */
    public XingePush() {
        xingeApp = new XingeApp(appId, secretKey);
    }

    /**
     * 指定api密钥创建xinge push
     */
    public XingePush(String appId, String secretKey) {
        this.appId = appId;
        this.secretKey = secretKey;
        xingeApp = new XingeApp(appId, secretKey);
    }

    /**
     * 推送到android指定的token设备
     * @param title 消息标题
     * @param content 消息正文
     * @param toList 推送的token
     */
    public boolean pushTokenOnAndroid(String title, String content, List<String> toList) {
        return pushMessage(RequestBuilder.android(title, content, AudienceType.token.getType(), toList));
    }
    /**
     * 推送到android指定的account设备
     * @param title 消息标题
     * @param content 消息正文
     * @param toList 推送的account
     */
    public boolean pushAccountOnAndroid(String title, String content, List<String> toList) {
        return pushMessage(RequestBuilder.android(title, content, AudienceType.account.getType(), toList));
    }
    /**
     * 推送到android的所有设备
     * @param title 消息标题
     * @param content 消息正文
     */
    public boolean pushAllOnAndroid(String title, String content) {
        return pushMessage(RequestBuilder.android(title, content));
    }
    /**
     * 推送到ios指定的token设备
     * @param title 消息标题
     * @param content 消息正文
     * @param toList 推送的token
     */
    public boolean pushTokenOnIos(String title, String content, List<String> toList) {
        return pushMessage(RequestBuilder.ios(title, content, AudienceType.token.getType(), toList));
    }
    /**
     * 推送到android指定的account设备
     * @param title 消息标题
     * @param content 消息正文
     * @param toList 推送的account
     */
    public boolean pushAccountOnIos(String title, String content, List<String> toList) {
        return pushMessage(RequestBuilder.ios(title, content, AudienceType.account.getType(), toList));
    }
    /**
     * 推送到ios指定的token设备
     * @param title 消息标题
     * @param content 消息正文
     */
    public boolean pushAllOnIos(String title, String content) {
        return pushMessage(RequestBuilder.ios(title, content));
    }
    /**
     * 消息推送
     */
    private boolean pushMessage(RequestBuilder requestBuilder) {
        PushAppRequest pushAppRequest = requestBuilder.createPushAppRequest();
        if(Objects.isNull(pushAppRequest)){
            return false;
        }
        String request = pushAppRequest.toString();
        //推送结果 0是推送成功 PushAppResponse
        /**
         * seq	int64_t	是	与请求包一致（如果请求包是非法json该字段为0）
         * push_id	string	是	推送id
         * ret_code	int32_t	是	错误码，详细参照错误码对照表
         * environment	string	是	用户指定推送环境，仅支持iOS product： 生产环境 dev： 开发环境
         * err_msg	string	否	请求出错时的错误信息
         * result	string	否	请求正确时，若有额外数据要返回，则结果封装在该字段的json中，若无额外数据，则可能无此字段
         *
         * {
         * 	"result": "[0]",
         * 	"environment": "product",
         * 	"push_id": "1079290952",
         * 	"err_msg": "",
         * 	"ret_code": 0,
         * 	"seq": 0
         * }
         */
        log.info("Pushing PushAppRequest: {}", request);
        try {
            JSONObject pushApp = xingeApp.pushApp(request);
            if (Objects.isNull(pushApp)) {
                return false;
            }
            log.info("Push complete and response: {}", pushApp.toString());
            PushAppResponse pushAppResponse = JSON.parseObject(pushApp.toString(), PushAppResponse.class);
            return pushAppResponse.getRet_code() == 0;
        } catch (Exception e) {
            log.error("Push fail, occur exception：", e);
            return false;
        }
    }

    @Data
    private static class RequestBuilder {
        /**
         * 消息标题
         */
        private String       title;
        /**
         * 消息内容
         */
        private String       content;
        /**
         * 消息推送的平台 1:android 2:ios
         */
        private Integer      platform;
        /**
         * 多种推送目标的，比如：全量、标签、单设备、设备列表、单账号、账号列表
         * 0 all 1 tag 2 token 3 token_list 4 account 5 account_list
         */
        private int          audienceType;
        /**
         * 发送的账号列表/token_list
         */
        private List<String> toList;

        private RequestBuilder(String title, String content, Integer platform, int audienceType){
            this.title = title;
            this.content = content;
            this.platform = platform;
            this.audienceType = audienceType;
        }
        private RequestBuilder(String title, String content, Integer platform, int audienceType, List<String> toList){
            this.title = title;
            this.content = content;
            this.platform = platform;
            this.audienceType = audienceType;
            this.toList = toList;
        }

        public static RequestBuilder android(String title, String content, int audienceType, List<String> toList) {
            return new RequestBuilder(title, content, Platform.android.getType(), audienceType, toList);
        }

        public static RequestBuilder android(String title, String content) {
            return new RequestBuilder(title, content, Platform.android.getType(), AudienceType.all.getType());
        }

        public static RequestBuilder ios(String title, String content, int audienceType, List<String> toList) {
            return new RequestBuilder(title, content, Platform.ios.getType(), audienceType, toList);
        }

        public static RequestBuilder ios(String title, String content) {
            return new RequestBuilder(title, content, Platform.ios.getType(), AudienceType.all.getType());
        }

        public boolean isAndroid() {
            return this.getPlatform() == Platform.android.getType();
        }

        public boolean isIos() {
            return this.getPlatform() == Platform.ios.getType();
        }

        public boolean isToken(){
            return this.audienceType == AudienceType.token.getType();
        }

        public boolean isAccount(){
            return this.audienceType == AudienceType.account.getType();
        }

        public boolean isAll(){
            return this.audienceType == AudienceType.all.getType();
        }

        public PushAppRequest createPushAppRequest() {
            /**
             * https://xg.qq.com/docs/server_api/v3/push_api_v3.html#message%EF%BC%9A%E6%B6%88%E6%81%AF%E4%BD%93
             */
            //推送请求信息
            PushAppRequest pushAppRequest = new PushAppRequest();
            /**
             * 消息类型
             1）notify：通知
             2）message：透传消息/静默消息
             */
            pushAppRequest.setMessage_type(MessageType.notify);
            /**
             * 指定推送时间
             * 1）格式为yyyy-MM-DD HH:MM:SS
             * 2）若小于服务器当前时间，则会立即推送
             * 3）仅全量推送和标签推送支持此字段
             */
            pushAppRequest.setSend_time(DateUtil.now());
            /**
             * 消息离线存储时间（单位为秒）,最长72小时
             * 1）若expire_time=0，则表示实时消息
             * 2）若expire_time大于0且小于800s，则系统会重置为800s
             * 3）若expire_time>=800s，按实际设置时间存储，最长72小时
             * 4)设置的最大值不得超过2147483647，否则会导致推送失败
             */
            //pushAppRequest.setExpire_time(24 * 60 * 60);
            /**
             * 循环任务重复次数
             * 1）仅支持全推、标签推
             * 2）建议取值[1, 15]
             */
            //pushAppRequest.setLoop_times(2);
            /**
             * 循环执行消息下发的间隔
             * 1）必须配合loop_times使用
             * 2）以天为单位，取值[1, 14]
             * 3）loop_times和loop_interval一起表示消息下发任务的循环规则
             */
            //pushAppRequest.setLoop_interval(2);
            /**
             * 客户端平台类型
             1）android：安卓
             2）ios：苹果
             */
            Message message = new Message();
            message.setTitle(this.getTitle());
            message.setContent(this.getContent());

            if (this.isAndroid()) {
                pushAppRequest.setPlatform(Platform.android);
                MessageAndroid messageAndroid = new MessageAndroid();
                /**
                 * 通知消息对象的唯一标识（只对信鸽通道生效）
                 * 1）大于0：会覆盖先前相同id的消息
                 * 2）等于0：展示本条通知且不影响其他消息
                 * 3）等于-1：将清除先前所有消息，仅展示本条消息
                 */
                messageAndroid.setN_id(0);
//                ClickAction clickAction = new ClickAction();
//                clickAction.setActivity("");
//                messageAndroid.setAction(clickAction);
                message.setAndroid(messageAndroid);
            } else if (this.isIos()) {
                pushAppRequest.setPlatform(Platform.ios);
                Alert alert = new Alert();
                alert.setTitle(this.getTitle());
                alert.setBody(this.getContent());
                Aps aps = new Aps();
                aps.setAlert(alert);
                MessageIOS messageIOS = new MessageIOS();
                messageIOS.setAps(aps);
                message.setIos(messageIOS);
            } else {
                log.error("Failed to Create PushAppRequest: Invalid platform type.(1:android, 2:ios)");
                return null;
            }
            pushAppRequest.setMessage(message);
            /**
             * 推送目标
             1）all：全量推送
             2）tag：标签推送
             3）token：单设备推送
             4）token_list：设备列表推送,最多1000 token
             5）account：单账号推送
             6）account_list：账号列表推送,最多1000 个account
             */
            if (this.isAll()) {
                pushAppRequest.setAudience_type(AudienceType.all);
                return pushAppRequest;
            } else {
                if (null == toList || toList.isEmpty()) {
                    log.error("Failed to Create PushAppRequest: 'toList' is null or empty when 'audienceType' is not 'ALL'.");
                    return null;
                }
                if(toList.size() > ValuePool.PUSH_MAX_SIZE){
                    log.error("Failed to Create PushAppRequest: the max size of 'toList' is 1000.");
                    return null;
                }
                if (this.isToken()) {
                    if (toList.size() == 1) {
                        pushAppRequest.setAudience_type(AudienceType.token);
                    } else {
                        pushAppRequest.setAudience_type(AudienceType.token_list);
                    }
                    pushAppRequest.setToken_list(new ArrayList<>(toList));
                    return pushAppRequest;
                } else if (this.isAccount()) {
                    if (toList.size() == 1) {
                        pushAppRequest.setAudience_type(AudienceType.account);
                    } else {
                        pushAppRequest.setAudience_type(AudienceType.account_list);
                    }
                    pushAppRequest.setAccount_list(new ArrayList<>(toList));
                    return pushAppRequest;
                } else {
                    log.error("Failed to Create PushAppRequest: 'audienceType' is not Invalid. (0:all, 2:token, 4:account)");
                    return null;
                }
            }

            //打印推送数据
            /**
             * {
             * 	"audience_type": "account",
             * 	"platform": "android",
             * 	"message_type": "notify",
             * 	"message": {
             * 		"title": "天域电梯测试",
             * 		"content": "测试信鸽消息推送，当前时间: 2019-12-24 17:03:15",
             * 		"accept_time": null,
             * 		"android": null,
             * 		"ios": null
             *        },
             * 	"expire_time": 259200,
             * 	"send_time": null,
             * 	"multi_pkg": false,
             * 	"loop_times": 0,
             * 	"loop_interval": 0,
             * 	"environment": "product",
             * 	"stat_tag": null,
             * 	"seq": 0,
             * 	"tag_list": null,
             * 	"account_list": ["18571500256"],
             * 	"account_type": 0,
             * 	"token_list": [],
             * 	"push_id": null
             * }
             */
        }
    }
}
