package cn.axzo.msg.center.message.service.impl;

import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.utils.PageHelperUtil;
import cn.axzo.msg.center.dal.BizEventMappingDao;
import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
import cn.axzo.msg.center.domain.entity.BizEventMapping;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.domain.enums.BizActionCategory;
import cn.axzo.msg.center.message.domain.param.BizEventMappingQueryParam;
import cn.axzo.msg.center.message.domain.param.BizEventSaveOrUpdateParam;
import cn.axzo.msg.center.message.service.BizEventMappingService;
import cn.axzo.msg.center.service.bizevent.request.BizEventMappingPageResponse;
import cn.axzo.msg.center.service.bizevent.request.BizEventMappingRemoveRequest;
import cn.axzo.msg.center.service.bizevent.request.ReachDto;
import cn.azxo.framework.common.model.Page;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author syl
 * @date 2023/12/14
 */
@Slf4j
@Service
public class BizEventMappingServiceImpl implements BizEventMappingService {

    @Autowired
    private BizEventMappingDao bizEventMappingDao;

    @Autowired
    private MessageBaseTemplateDao messageBaseTemplateDao;

    @Override
    public String create(BizEventSaveOrUpdateParam param) {
        // BizCode校验
        checkCreateBizCode(param);
        // 消息模板校验
        param.getReachConfig().forEach(this::checkTemplateCodeByBizEvent);

        BizEventMapping eventMapping = BizEventMapping.builder()
                .bizCode(param.getBizCode())
                .bizName(param.getBizName())
                .reachConfig(param.getReachConfig())
                .creatorId(param.getOperatorId())
                .build();
        bizEventMappingDao.save(eventMapping);
        return eventMapping.getBizCode();
    }

    private void checkCreateBizCode(BizEventSaveOrUpdateParam param) {
        List<BizEventMapping> bizEvents = build(BizEventMappingQueryParam.builder()
                .bizCode(param.getBizCode()).build()).list();
        AssertUtil.isTrue(CollUtil.isEmpty(bizEvents), "编码code已存在");
    }

    @Override
    public void update(BizEventSaveOrUpdateParam param) {
        // BizCode校验
        BizEventMapping exist = checkUpdateBizCodeParam(param);
        // 消息模板校验
        if (CollUtil.isNotEmpty(param.getReachConfig())) {
            param.getReachConfig().forEach(this::checkTemplateCodeByBizEvent);
        }

        bizEventMappingDao.updateById(param.convertUpdateEntity(exist));
    }

    private BizEventMapping checkUpdateBizCodeParam(BizEventSaveOrUpdateParam param) {
        if (Objects.nonNull(param.getId())) {
            BizEventMapping exist = bizEventMappingDao.getById(param.getId());
            AssertUtil.notNull(exist, "业务事件不存在");
            // 检查bizCode
            if (StringUtils.isNotBlank(param.getBizCode())) {
                List<BizEventMapping> otherEvents = build(BizEventMappingQueryParam.builder()
                        .excludeId(param.getId())
                        .bizCode(param.getBizCode()).build()).list();
                AssertUtil.isEmpty(otherEvents, "编码code已存在");
            }
            return exist;
        }
        List<BizEventMapping> bizEvents = build(BizEventMappingQueryParam.builder()
                .bizCode(param.getBizCode()).build()).list();
        AssertUtil.notEmpty(bizEvents, "编码code不存在");
        return bizEvents.stream().findFirst().get();
    }

    @Override
    public Page<BizEventMappingPageResponse> page(BizEventMappingQueryParam param) {
        IPage<BizEventMapping> result = build(param).page(param.toPage());
        if (Objects.isNull(result) || CollUtil.isEmpty(result.getRecords())) {
            return PageHelperUtil.emptyPage(param.getPage(), param.getPageSize());
        }
        List<BizEventMappingPageResponse> records = BeanUtil.copyToList(result.getRecords(),
                BizEventMappingPageResponse.class);
        return Page.toPage(param.getPage(), param.getPageSize(), result.getTotal(), records);
    }

    @Override
    public void remove(BizEventMappingRemoveRequest param) {
        // BizCode校验
        log.info("remove BizEventMapping: bizCode= [{}]", param.getId());
        this.update(BizEventSaveOrUpdateParam.builder()
                .id(param.getId())
                .operatorId(param.getOperatorId())
                .isDelete(true).build());
    }

    @Override
    public Optional<BizEventMapping> getByBizCode(String bizCode) {
        return build(BizEventMappingQueryParam.builder()
                .bizCode(bizCode).build())
                .last("LIMIT 1")
                .oneOpt();
    }

    @Override
    public MessageBaseTemplate checkTemplateCodeByBizEvent(ReachDto config) {
        BizActionCategory category = BizActionCategory.getCategory(config.getCategory());
        Optional<MessageBaseTemplate> templateOpt = messageBaseTemplateDao.lambdaQuery()
                .eq(MessageBaseTemplate::getCode, config.getTemplateCode())
                .in(MessageBaseTemplate::getMsgCategory, category.getBizCategoryList())
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .oneOpt();
        AssertUtil.isTrue(templateOpt.isPresent(), String.format("消息模板code不存在或类型不匹配: %s",
                config.getTemplateCode()));
        return templateOpt.get();
    }

    public LambdaQueryChainWrapper<BizEventMapping> build(BizEventMappingQueryParam bo) {
        return bizEventMappingDao.lambdaQuery()
                .eq(Objects.nonNull(bo.getId()), BizEventMapping::getId, bo.getId())
                .eq(StringUtils.isNotBlank(bo.getBizCode()), BizEventMapping::getBizCode,
                        bo.getBizCode())
                .ne(Objects.nonNull(bo.getExcludeId()), BizEventMapping::getId, bo.getExcludeId())
                .eq(BizEventMapping::getIsDelete, 0)
                .and(StringUtils.isNotBlank(bo.getBizNameLike()),
                        o -> o.like(BizEventMapping::getBizName, bo.getBizNameLike()))
                .and(StringUtils.isNotBlank(bo.getTemplateCode()),
                        w -> w.apply("  JSON_CONTAINS(`reach_config`, JSON_OBJECT('templateCode',{0}))", bo.getTemplateCode()))
                .orderByDesc(BizEventMapping::getCreateAt);
    }
}
