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

import cn.axzo.msg.center.api.InsideMessageModuleApi;
import cn.axzo.msg.center.api.enums.ReceiveTypeEnum;
import cn.axzo.msg.center.api.request.CreateModuleReq;
import cn.axzo.msg.center.api.request.SearchModuleReq;
import cn.axzo.msg.center.api.request.SyncModuleDataReq;
import cn.axzo.msg.center.api.request.UpdateModuleReq;
import cn.axzo.msg.center.api.response.CommonPlatManagerRes;
import cn.axzo.msg.center.api.response.MessageModuleRes;
import cn.axzo.msg.center.api.response.ModuleGroupByNameResponse;
import cn.axzo.msg.center.api.response.SyncModuleDataRes;
import cn.axzo.msg.center.api.response.SyncRouterDataRes;
import cn.axzo.msg.center.api.response.SyncTemplateDataRes;
import cn.axzo.msg.center.common.utils.BeanConvertUtils;
import cn.axzo.msg.center.domain.dto.CreateModuleDTO;
import cn.axzo.msg.center.domain.dto.SearchModuleDTO;
import cn.axzo.msg.center.domain.dto.SyncModuleDataDTO;
import cn.axzo.msg.center.domain.dto.UpdateModuleDTO;
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.enums.UserTypeEnum;
import cn.axzo.msg.center.domain.request.inside.SearchModuleVO;
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 com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RestController
public class InsideMessageModuleApiImpl implements InsideMessageModuleApi {

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

    @Override
    public CommonResponse<Map<Long, String>> getModules(@PathVariable Integer identityType) {
        Map<Long, String> moduleMap = new HashMap<>();
        List<MessageModule> modules = moduleService.listModuleByUserType(
                UserTypeEnum.valueOf(identityType));
        modules.forEach(i -> {
            moduleMap.put(i.getId(), i.getModuleName());
        });
        return CommonResponse.success(moduleMap);
    }

    @Override
    public CommonResponse<List<MessageModuleRes>> listModuleByUserType(Integer identityType) {
        List<MessageModuleRes> result=new ArrayList<>();
        List<MessageModule> modules = moduleService.listModuleByUserType(
                UserTypeEnum.valueOf(identityType));
        if (CollectionUtils.isEmpty(modules)) {
            return CommonResponse.success(null);
        }
        for (MessageModule module : modules) {
            MessageModuleRes item = BeanConvertUtils.copyBean(module, MessageModuleRes.class);
            result.add(item);
        }
        return CommonResponse.success(result);
    }

    @Override
    public CommonResponse<CommonPlatManagerRes> listModules(Integer identityType) {
        List modules = moduleService.listModuleByUserType(UserTypeEnum.getByName(ReceiveTypeEnum.valueOf(identityType).getMessage()));
        CommonPlatManagerRes result = new CommonPlatManagerRes();
        result.setList(modules);
        return CommonResponse.success(result);
    }


    @Override
    public CommonResponse<CommonPlatManagerRes> pageModules(SearchModuleReq req) {
        SearchModuleDTO request=new SearchModuleDTO();
        BeanUtils.copyProperties(req, request);
        IPage<MessageModule> page = moduleService.page(request);
        List vos = new ArrayList<>();
        page.getRecords().forEach(i -> {
            SearchModuleVO vo = new SearchModuleVO();
            vo.setEnv(Arrays.asList(environment.getActiveProfiles()).toString());
            vo.setId(i.getId());
            vo.setModuleName(i.getModuleName());
            vo.setIcon(i.getIcon());
            vo.setRemark(i.getRemark());
            vo.setOwnedType(i.getOwnedType().getCode());
            vo.setBizType(i.getBizType().getCode());
            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);
    }

    @Override
    public CommonResponse<String> addModule(CreateModuleReq req) {
        CreateModuleDTO request=new UpdateModuleDTO();
        BeanUtils.copyProperties(req, request);
        moduleService.add(request);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<String> updateModule(UpdateModuleReq req) {
        UpdateModuleDTO request=new UpdateModuleDTO();
        BeanUtils.copyProperties(req, request);
        moduleService.update(request);
        return CommonResponse.success();
    }

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

    @Override
    public CommonResponse<List<SyncModuleDataRes>> findModuleByIds(List<Long> ids) {
        List<SyncModuleDataRes> result = new ArrayList<>();
        // 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 -> {
            SyncModuleDataRes relation = new SyncModuleDataRes();
            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);
    }

    @Override
    public CommonResponse<Void> syncData(List<SyncModuleDataReq> dtoList) {
        if(CollectionUtils.isEmpty(dtoList)){
            log.warn("module syncData  dtoList is empty");
            return CommonResponse.success();
        }
        List<SyncModuleDataDTO> syncModuleDataDTOS = BeanConvertUtils.copyList(dtoList, SyncModuleDataDTO.class);
        moduleService.syncData(syncModuleDataDTOS);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<List<ModuleGroupByNameResponse>> listModulesGroupByName() {
        Map<String, List<Long>> resultList = groupByField(MessageModule::getModuleName);
        List<ModuleGroupByNameResponse> responses = resultList.entrySet().stream()
                .filter(e -> !"项目公告".equals(e.getKey()))
                .map(e -> ModuleGroupByNameResponse.builder()
                        .moduleName(e.getKey())
                        .ids(e.getValue())
                        .build())
                .collect(Collectors.toList());
        return CommonResponse.success(responses);
    }

    private <T> Map<T, List<Long>> groupByField(Function<MessageModule, T> groupByField) {
        if (Objects.isNull(groupByField)) {
            log.warn("groupByField is null...");
            return Collections.emptyMap();
        }
        return moduleService.getAllModules().stream()
                .collect(Collectors.groupingBy(groupByField,
                        Collectors.mapping(MessageModule::getId, Collectors.toList())));
    }
}
