package cn.axzo.msg.center.inside.notices.service.impl;

import cn.axzo.msg.center.api.InsideMessageTemplateApi;
import cn.axzo.msg.center.api.request.*;
import cn.axzo.msg.center.api.response.*;
import cn.axzo.msg.center.common.utils.BeanConvertUtils;
import cn.axzo.msg.center.common.utils.CustomBeanUtils;
import cn.axzo.msg.center.domain.dto.SearchTemplateDTO;
import cn.axzo.msg.center.domain.dto.SyncRelationDataDTO;
import cn.axzo.msg.center.domain.dto.SyncRouterDataDTO;
import cn.axzo.msg.center.domain.dto.SyncTemplateDataDTO;
import cn.axzo.msg.center.domain.entity.MessageModule;
import cn.axzo.msg.center.domain.entity.MessageRelation;
import cn.axzo.msg.center.domain.entity.MessageRouter;
import cn.axzo.msg.center.domain.entity.MessageTemplate;
import cn.axzo.msg.center.domain.request.inside.MessageRouterVo;
import cn.axzo.msg.center.domain.request.inside.SearchTemplateVO;
import cn.axzo.msg.center.inside.notices.service.MessageModuleService;
import cn.axzo.msg.center.inside.notices.service.MessageRelationService;
import cn.axzo.msg.center.inside.notices.service.MessageRouterService;
import cn.axzo.msg.center.inside.notices.service.MessageTemplateService;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@Slf4j
public class InsideMessageTemplateApiImpl implements InsideMessageTemplateApi {

    @Resource
    private MessageModuleService moduleService;
    @Resource
    private MessageRelationService relationService;
    @Resource
    private MessageTemplateService templateService;
    @Resource
    private MessageRouterService routerService;

    @Resource
    private Environment environment;


    @Override
    public CommonResponse<String> addTemplate(CreateTemplateReq req) {
        relationService.createTemplate(req);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<String> updateTemplate(UpdateTemplateReq req) {
        relationService.updateTemplate(req);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<String> updateTemplateAudioFile(UpdateTemplateAudioFileReq req) {
        relationService.updateTemplateAudioFile(req);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<CommonPlatManagerRes> pageTemplates(SearchTemplateReq req) {
        SearchTemplateDTO dto= BeanConvertUtils.copyBean(req,SearchTemplateDTO.class);
        if(StringUtils.hasLength(req.getTitle()) || StringUtils.hasLength(req.getContent())) {
            List<MessageTemplate> templates = templateService.getListByTitleAndContent(dto);
            if(!CollectionUtils.isEmpty(templates)) {
                dto.setInnerTemplateIds(templates.stream().map(MessageTemplate::getId).collect(Collectors.toList()));
            }
        }
        IPage<MessageRelation> page = relationService.page(dto);
        List<Long> templateIds = page.getRecords().stream().map(MessageRelation::getTemplateId)
                .collect(Collectors.toList());
        Set<Long> relationIds = page.getRecords().stream().map(MessageRelation::getId)
                .collect(Collectors.toSet());
        // 模板
        Map<Long, MessageTemplate> templateMap = templateService.getTemplateByIds(templateIds).stream()
                .collect(Collectors.toMap(MessageTemplate::getId, Function.identity(), (s, t) -> s));
        Map<Long, MessageModule> moduleMap = moduleService.getAllModules().stream()
                .collect(Collectors.toMap(MessageModule::getId, Function.identity(), (s, t) -> s));
        Map<Long, List<MessageRouter>> routerMap = routerService.listRoutersByRelationIds(relationIds)
                .stream().collect(Collectors.groupingBy(
                        MessageRouter::getRelationId));

        List vos = new ArrayList<>();
        page.getRecords().forEach(i -> {
            SearchTemplateVO vo = new SearchTemplateVO();
            MessageModule emptyModule = new MessageModule();
            MessageTemplate emptyTemplate = new MessageTemplate();
            vo.setEnv(Arrays.asList(environment.getActiveProfiles()).toString());
            vo.setRelationId(i.getId());
            vo.setContactUser(i.getContactUser());
            vo.setModuleId(i.getModuleId());
            if(Objects.nonNull(moduleMap.getOrDefault(i.getModuleId(), emptyModule).getBizType())) {
                vo.setBizType(moduleMap.getOrDefault(i.getModuleId(), emptyModule).getBizType().getCode());
            }
            vo.setModuleName(moduleMap.getOrDefault(i.getModuleId(), emptyModule).getModuleName());
            vo.setTitle(templateMap.getOrDefault(i.getTemplateId(), emptyTemplate).getTitle());
            vo.setContent(templateMap.getOrDefault(i.getTemplateId(), emptyTemplate).getContent());
            if (Objects.nonNull(moduleMap.getOrDefault(i.getModuleId(), emptyModule).getOwnedType())) {
                vo.setReceiveIdentityType(
                        moduleMap.getOrDefault(i.getModuleId(), emptyModule).getOwnedType().getCode());
            }
            List<MessageRouterRes> messageRouterRes = parseRouters(routerMap.getOrDefault(i.getId(), Lists.newArrayList()));
            List<MessageRouterVo> messageRouterVos = CustomBeanUtils.copyListProperties(messageRouterRes, MessageRouterVo::new);
            vo.setRouters(messageRouterVos);
            vo.setCreateAt(i.getCreateAt());
            vo.setUpdateAt(i.getUpdateAt());
            vos.add(vo);
        });
        CommonPlatManagerRes result = new CommonPlatManagerRes();
        result.setList(vos);
        result.setPage(Math.toIntExact(page.getPages()));
        result.setPageSize(Math.toIntExact(page.getSize()));
        result.setTotalCount(Math.toIntExact(page.getTotal()));
        return CommonResponse.success(result);
    }

    private List<MessageRouterRes> parseRouters(List<MessageRouter> routers) {
        List<MessageRouterRes> vos = new ArrayList<>();
        routers.forEach(i -> {
            MessageRouterRes vo = new MessageRouterRes();
            vo.setId(i.getId());
            vo.setType(i.getRouterType().getCode());
            vo.setUrl(i.getRouterUrl());
            vos.add(vo);
        });
        return vos;
    }

    @Override
    public CommonResponse<SearchTemplateRes> get(Long id) {
        MessageRelation mr = relationService.getRelationById(id);
        MessageTemplate mt = templateService.getTemplateById(mr.getTemplateId());
        MessageModule mm = moduleService.getModuleById(mr.getModuleId());
        List<MessageRouter> routers = routerService.getRoutersByRelationId(mr.getId());
        SearchTemplateRes templateResponse = new SearchTemplateRes();
        templateResponse.setRelationId(mr.getId());
        templateResponse.setModuleId(mr.getModuleId());
        templateResponse.setContactUser(mr.getContactUser());
        templateResponse.setTitle(mt.getTitle());
        templateResponse.setContent(mt.getContent());
        Optional.ofNullable(mm).ifPresent(i->{
            templateResponse.setModuleName(mm.getModuleName());
            templateResponse.setReceiveIdentityType(mm.getOwnedType().getCode());
        });
        templateResponse.setRouters(parseRouters(routers));
        templateResponse.setCreateAt(mr.getCreateAt());
        templateResponse.setUpdateAt(mr.getUpdateAt());
        return CommonResponse.success(templateResponse);
    }

    @Override
    public CommonResponse<Void> delete(Long id) {
        relationService.delete(id);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<String> syncTemplateData(List<SyncRelationDataReq> syncRelationDataReqList) {
        if(CollectionUtils.isEmpty(syncRelationDataReqList)){
            log.warn("syncTemplateData syncRelationDataReqList is empty");
            return CommonResponse.success();
        }
        List<SyncRelationDataDTO> requestList = convert2SyncRelationDataDTOList(syncRelationDataReqList);
        relationService.syncData(requestList);
        return CommonResponse.success();
    }

    private List<SyncRelationDataDTO> convert2SyncRelationDataDTOList(List<SyncRelationDataReq> syncRelationDataReqList){
        List<SyncRelationDataDTO> result=new ArrayList<>();
        for (SyncRelationDataReq item : syncRelationDataReqList) {
            SyncRelationDataDTO syncRelationDataDTO = BeanConvertUtils.copyBean(item, SyncRelationDataDTO.class);
            if(item.getTemplate()!=null){
                SyncTemplateDataDTO syncTemplateDataDTO = BeanConvertUtils.copyBean(item.getTemplate(), SyncTemplateDataDTO.class);
                syncRelationDataDTO.setTemplate(syncTemplateDataDTO);
            }
            if(!CollectionUtils.isEmpty(item.getRouters())){
                List<SyncRouterDataDTO> routerList=new ArrayList<>();
                for (SyncRouterDataReq router : item.getRouters()) {
                    SyncRouterDataDTO syncRouterDataDTO = BeanConvertUtils.copyBean(router, SyncRouterDataDTO.class);
                    routerList.add(syncRouterDataDTO);
                }
                syncRelationDataDTO.setRouters(routerList);
            }
            result.add(syncRelationDataDTO);
        }
        log.info("syncRelationDataReqList value={},result value={}", JSONUtil.toJsonStr(syncRelationDataReqList),JSONUtil.toJsonStr(result));
        return result;
    }

    @Override
    public CommonResponse<List<SyncRelationDataRes>> findTemplateByIds(@RequestParam("ids") List<Long> ids) {
        List<SyncRelationDataRes> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(ids)) {
            return CommonResponse.success();
        }
        // process relation
        List<MessageRelation> mrs = relationService.getRelationByIds(new HashSet<>(ids));

        // process template
        List<Long> mtIds = mrs.stream().map(MessageRelation::getTemplateId)
                .collect(Collectors.toList());
        Map<Long, MessageTemplate> mtMaps = templateService.getTemplateByIds(mtIds).stream()
                .collect(Collectors.toMap(
                        MessageTemplate::getId, Function.identity(), (s, t) -> s));

        // process module
        Map<Long, List<MessageRouter>> routerMaps = routerService.getRouterMapByRelationIds(
                ids).stream().collect(Collectors.groupingBy(MessageRouter::getRelationId));

        // general data
        mrs.forEach(i -> {
            SyncRelationDataRes relation = new SyncRelationDataRes();
            relation.setId(i.getId());
            relation.setModuleId(i.getModuleId());
            relation.setTemplateId(i.getTemplateId());
            relation.setContactUser(i.getContactUser());

            SyncTemplateDataRes template = new SyncTemplateDataRes();
            MessageTemplate tempMT;
            if (Objects.nonNull(tempMT = mtMaps.getOrDefault(i.getTemplateId(), null))) {
                template.setId(tempMT.getId());
                template.setTitle(tempMT.getTitle());
                template.setContent(tempMT.getContent());
            }
            relation.setTemplate(template);

            List<SyncRouterDataRes> routers = new ArrayList<>();
            List<MessageRouter> tempRouters;
            if (!CollectionUtils.isEmpty(
                    tempRouters = routerMaps.getOrDefault(i.getId(), new ArrayList<>()))) {
                tempRouters.forEach(mr -> {
                    SyncRouterDataRes router = new SyncRouterDataRes();
                    router.setId(mr.getId());
                    router.setRelationId(mr.getRelationId());
                    router.setRouterType(mr.getRouterType().getCode());
                    router.setRouterUrl(mr.getRouterUrl());
                    routers.add(router);
                });
            }
            relation.setRouters(routers);
            result.add(relation);
        });

        return CommonResponse.success(result);
    }
}
