package cn.axzo.msg.center.message.xxl;

import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.maokai.api.util.Ref;
import cn.axzo.msg.center.dal.CardStyleDao;
import cn.axzo.msg.center.dal.MessageTemplateV3Dao;
import cn.axzo.msg.center.domain.entity.CardStyle;
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.MessageChannel;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
import com.alibaba.fastjson.JSON;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

import static java.util.stream.Collectors.toList;

@Slf4j
@Component
@RequiredArgsConstructor
@RefreshScope
public class UpdateTemplateV3ChannelStyleVersionJob  extends IJobHandler {

    private final MessageTemplateV3Dao messageTemplateV3Dao;

    private final CardStyleDao cardStyleDao;

    /**
     * 注意:线上卡片样式初始化保持一致
     * 即 card_style#code初始化时一定是 60d52877f3e2424380c3353baca3810c
     */
    @Value("${card.style.code:common_style_001}")
    private String cardStyleCode;

    @XxlJob("updateTemplateV3ChannelStyleVersionJob")
    @Override
    public ReturnT<String> execute(String param) throws Exception {
        //1 解析参数
        ParamParse paramParse = null;
        if (StringUtils.hasText(param)) {
            paramParse = JSON.parseObject(param, ParamParse.class);
        }
        // 2-1 根据指定的code更新
        if (Objects.nonNull(paramParse) && !CollectionUtils.isEmpty(paramParse.getCodes())) {
            this.doUpdateByCodes(paramParse);
            return ReturnT.SUCCESS;
        }
        // 2-2 全量更新
        this.doUpdateAll();

        return ReturnT.SUCCESS;
    }

    /**
     * 全量更新
     */
    private void doUpdateAll() {
        CardStyle cardStyle = this.getCardStyleByCode(cardStyleCode);

        Supplier<List<MessageTemplateV3>> cursor = templateV3sCursor();
        int count = 0;
        for (List<MessageTemplateV3> templateV3List = cursor.get(); !templateV3List.isEmpty(); templateV3List = cursor.get()) {
            XxlJobLogger.log("update MessageTemplateV3 info, count: {},v3List:{}", count += templateV3List.size(), JSON.toJSONString(templateV3List));
            if (Objects.isNull(cardStyle) || !StringUtils.hasText(cardStyle.getCode())) {
                XxlJobLogger.log("doUpdateAll cardStyle is null continue");
                continue;
            }
            //更新逻辑
            this.updateTemplateV3ChannelStyleVersion(templateV3List, cardStyleCode, cardStyle.getElementConfigs());
        }
        XxlJobLogger.log("doUpdateAll end");
    }

    /**
     * 通过code获取卡片样式
     */
    private CardStyle getCardStyleByCode(String code) {
        return cardStyleDao.lambdaQuery().eq(CardStyle::getCode, code).one();
    }

    /**
     * 根据指定的code更新
     */
    public void doUpdateByCodes(ParamParse paramParse) {
        CardStyle cardStyle = this.getCardStyleByCode(cardStyleCode);
        XxlJobLogger.log("根据codes更新im账号-start,ids:{}", paramParse.getCodes());
        List<MessageTemplateV3> templateV3List = messageTemplateV3Dao
                .lambdaQuery()
                .in(MessageTemplateV3::getCode, paramParse.getCodes())
                .eq(MessageTemplateV3::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .orderByAsc(MessageTemplateV3::getId)
                .list();
        if (Objects.isNull(cardStyle) || !StringUtils.hasText(cardStyle.getCode())) {
            XxlJobLogger.log("doUpdateByCodes cardStyle is null return");
            return;
        }
        //更新逻辑
        this.updateTemplateV3ChannelStyleVersion(templateV3List, cardStyleCode, cardStyle.getElementConfigs());
        XxlJobLogger.log("根据codes更新-end,codes:{}", CollectionUtils.isEmpty(templateV3List) ? "" : templateV3List.stream().map(MessageTemplateV3::getCode).collect(toList()));
    }

    /**
     * 更新 卡片样式code/卡片样式扩展字段/通道/端对应最低版本
     * @param templateV3List 消息模版
     * @param updateCardStyleCode 卡片样式
     * @param updateCardExtFields 卡片样式扩展字段
     */
    public void updateTemplateV3ChannelStyleVersion(List<MessageTemplateV3> templateV3List
            , String updateCardStyleCode, List<CardElementConfig> updateCardExtFields) {
        if (CollectionUtils.isEmpty(templateV3List)) {
            return;
        }
        for (MessageTemplateV3 templateV3 : templateV3List) {
            //构建通道
            List<MessageChannel> updateChannels = this.buildMessageChannel(templateV3);
            //构建端对应最低版本
            List<AppVersionConfig> updateAppVersionConfigs = this.buildAppVersionConfig(templateV3);

            boolean updateFlag = ((Objects.nonNull(updateChannels) && CollectionUtils.isEmpty(templateV3.getChannels()))
                                    || (StringUtils.hasText(updateCardStyleCode) && !StringUtils.hasText(templateV3.getCardStyleCode()))
                                    || (Objects.nonNull(updateCardExtFields) && CollectionUtils.isEmpty(templateV3.getCardExtFields()))
                                    || (Objects.nonNull(updateAppVersionConfigs) && CollectionUtils.isEmpty(templateV3.getAppVersionConfigs()))
                                    || CollectionUtils.isEmpty(templateV3.getStateImageConfigs()));
            if (updateFlag) {
                messageTemplateV3Dao.lambdaUpdate().eq(MessageTemplateV3::getId, templateV3.getId())
                        // 通道:IM/待办
                        .set(Objects.nonNull(updateChannels) && CollectionUtils.isEmpty(templateV3.getChannels()), MessageTemplateV3::getChannels, JSON.toJSONString(updateChannels))
                        // 卡片样式编码
                        .set(StringUtils.hasText(updateCardStyleCode) && !StringUtils.hasText(templateV3.getCardStyleCode()), MessageTemplateV3::getCardStyleCode, updateCardStyleCode)
                        // 卡片样式扩展字段
                        .set(Objects.nonNull(updateCardExtFields) && CollectionUtils.isEmpty(templateV3.getCardExtFields()), MessageTemplateV3::getCardExtFields, JSON.toJSONString(updateCardExtFields))
                        // 端对应最低版本
                        .set(Objects.nonNull(updateAppVersionConfigs) && CollectionUtils.isEmpty(templateV3.getAppVersionConfigs()), MessageTemplateV3::getAppVersionConfigs, JSON.toJSONString(updateAppVersionConfigs))
                        // 卡片状态图片配置
                        .set(CollectionUtils.isEmpty(templateV3.getStateImageConfigs()), MessageTemplateV3::getStateImageConfigs, JSON.toJSONString(Lists.newArrayList()))
                        .update();
            }
        }
    }

    /**
     * 构建通道
     */
    private List<MessageChannel> buildMessageChannel(MessageTemplateV3 templateV3) {
        List<MessageChannel> updateChannels = Lists.newArrayList();

        switch (templateV3.getMsgCategory()) {
            case GENERAL_MESSAGE:
                updateChannels.add(MessageChannel.IM);
                break;
            case BIZ_PENDING_MESSAGE:
            case APPROVAL_PENDING_MESSAGE:
            case IM_MESSAGE_CARD:
                updateChannels.add(MessageChannel.TODO);
        }
        return updateChannels;
    }

    /**
     * 构建端对应最低版本
     */
    private List<AppVersionConfig> buildAppVersionConfig(MessageTemplateV3 templateV3) {
        List<AppVersionConfig> updateAppVersionConfigs = Lists.newArrayList();
        String minAppVersion = templateV3.getMinAppVersion();
        List<PushTerminalEnum> pushTerminalEnums = JSON.parseArray(templateV3.getPushTerminal(), PushTerminalEnum.class);
        if (!CollectionUtils.isEmpty(pushTerminalEnums)) {
            pushTerminalEnums.stream().forEach(item -> {

                AppTypeEnum appType = item.toAppType();
                if (Objects.nonNull(appType)) {
                    AppVersionConfig appVersionConfig = new AppVersionConfig();
                    appVersionConfig.setAppType(appType);
                    appVersionConfig.setMinVersion(StringUtils.hasText(minAppVersion) ? minAppVersion : "");

                    updateAppVersionConfigs.add(appVersionConfig);
                }
            });
        }
        return updateAppVersionConfigs;
    }

    private Supplier<List<MessageTemplateV3>> templateV3sCursor() {
        Ref<Long> maxId = Ref.create(0L);
        return () -> {
            List<MessageTemplateV3> accounts = messageTemplateV3Dao
                    .lambdaQuery()
                    .eq(MessageTemplateV3::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                    .gt(MessageTemplateV3::getId, maxId.get())
                    .orderByAsc(MessageTemplateV3::getId)
                    .last("LIMIT 200")
                    .list();
            if (!accounts.isEmpty()) {
                maxId.set(accounts.get(accounts.size() - 1).getId());
                log.info("update cursor id to: {}", maxId.get());
            }
            return accounts;
        };
    }

    @Data
    public static class ParamParse {
        private List<String> codes;
    }
}
