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

import cn.axzo.msg.center.api.MNSNoticesApi;
import cn.axzo.msg.center.api.MessageAPIV3;
import cn.axzo.msg.center.api.request.AddMnsChannelRequest;
import cn.axzo.msg.center.api.request.MnsSendCodeV2Req;
import cn.axzo.msg.center.api.request.SendMessageRequestDto;
import cn.axzo.msg.center.api.request.UpdateMnsTemplateContentRequest;
import cn.axzo.msg.center.api.request.v3.MessageSendReqV3;
import cn.axzo.msg.center.api.request.v3.SearchMessageReqV3;
import cn.axzo.msg.center.api.request.v3.SearchPendingMessageReq;
import cn.axzo.msg.center.api.request.v3.SearchTodoLogReq;
import cn.axzo.msg.center.api.request.v3.SetImSendPriorityRequest;
import cn.axzo.msg.center.api.request.v3.UpdateMnsChannelTemplateRequest;
import cn.axzo.msg.center.dal.MNSMessageTemplateDao;
import cn.axzo.msg.center.domain.entity.MNSMessageTemplate;
import cn.axzo.msg.center.im.service.IMService;
import cn.axzo.msg.center.inside.notices.service.impl.TodoSearchService;
import cn.axzo.msg.center.inside.notices.service.impl.v3.MessageRecordServiceV3;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
import cn.axzo.msg.center.message.service.impl.person.PersonService;
import cn.axzo.msg.center.message.service.todo.manage.TodoManager;
import cn.axzo.msg.center.message.xxl.MigrateOldMsgHotDataJob;
import cn.axzo.msg.center.notices.manager.api.MessageChannelRouter;
import cn.axzo.msg.center.notices.manager.api.MessageTemplateManager;
import cn.axzo.msg.center.notices.manager.api.dto.request.plat.CreateTemplateRequestDto;
import cn.axzo.msg.center.notices.service.api.PlatService;
import cn.axzo.msg.center.service.pending.request.RevokeByTemplateCodeRequest;
import cn.axzo.trade.web.annotation.EnableResponseAdvice;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.DumperOptions;

import javax.validation.Valid;
import java.util.Map;

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

/**
 * @author syl
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/private/message")
public class PrivateMessageController {

    private final MessageRecordServiceV3 messageRecordServiceV3;
    private final MessageAPIV3 messageAPIV3;
    private final TodoSearchService todoSearchService;
    private final TodoManager todoManager;
    private final GroupTemplateService groupTemplateService;
    private final MigrateOldMsgHotDataJob migrateOldMsgHotDataJob;
    private final PersonService personService;
    private final IMService imService;
    private final MessageTemplateManager messageTemplateManager;
    private final PlatService platService;
    private final ConfigurableEnvironment configurableEnvironment;
    private final MNSNoticesApi mnsNoticesApi;
    private final MessageChannelRouter messageChannelRouter;
    private final MNSMessageTemplateDao mnsMessageTemplateDao;

    @PostMapping("/sendPendingMessage")
    @EnableResponseAdvice(enable = false)
    public Object sendPendingMessage(@RequestBody @Valid PendingMessagePushParam request) {
        return todoManager.send(request);
    }

    @PostMapping("/revokeTodoByTemplateCode")
    @EnableResponseAdvice(enable = false)
    public Object revokeTodoByTemplateCode(@RequestBody @Valid RevokeByTemplateCodeRequest request) {
        return todoManager.revokeByTemplateCode(request);
    }

    @PostMapping("/sendByEventMapping")
    @EnableResponseAdvice(enable = false)
    public Object sendByEventMapping(@RequestBody @Valid MessageSendReqV3 request) {
        return messageAPIV3.send(request);
    }

    @PostMapping("/searchImRecord")
    @EnableResponseAdvice(enable = false)
    public Object searchImRecord(@RequestBody @Valid SearchMessageReqV3 req) {
        return messageRecordServiceV3.search(req);
    }

    @PostMapping("/searchTodos")
    @EnableResponseAdvice(enable = false)
    public Object searchTodos(@RequestBody @Valid SearchPendingMessageReq req) {
        return todoSearchService.searchTodos(req);
    }

    @PostMapping("/searchTodoLogs")
    @EnableResponseAdvice(enable = false)
    public Object searchTodoLogs(@RequestBody @Valid SearchTodoLogReq req) {
        return todoSearchService.searchTodoLogs(req);
    }

    @PostMapping("/getGroupTemplates")
    @EnableResponseAdvice(enable = false)
    public Object getGroupTemplates(@RequestParam("groupNodeCode") String groupNodeCode) {
        return groupTemplateService.collectTemplateCodes(groupNodeCode);
    }

    @PostMapping("/getPersonIdByPhone")
    @EnableResponseAdvice(enable = false)
    public Object getPersonIdByPhone(@RequestParam("phone") String phone) {
        return personService.getPersonIdByPhone(phone).orElse(null);
    }

    @PostMapping("/getPhoneByPersonId")
    @EnableResponseAdvice(enable = false)
    public Object getPhoneByPersonId(@RequestParam("personId") Long personId) {
        return personService.getPhoneByPersonId(personId).orElse(null);
    }

    /**
     * 因为没有权限了, 用于查看nacos是否配置了正确的值
     */
    @PostMapping("/readNacosConfig")
    @EnableResponseAdvice(enable = false)
    public Object readNacosConfig() throws Exception {
        DumperOptions options = new DumperOptions();
        options.setPrettyFlow(true);
        options.setSplitLines(true);
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
        Map<String, ?> map = configurableEnvironment.getPropertySources().stream()
                .filter(source -> source instanceof BootstrapPropertySource)
                .collect(toMap(PropertySource::getName, PropertySource::getSource));
        YAMLFactory yamlFactory = new YAMLFactory()
                .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
                .disable(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE);
        return new ObjectMapper(yamlFactory).writeValueAsString(map);
    }

    @PostMapping("/migrateOldMsgHotData")
    @EnableResponseAdvice(enable = false)
    public Object migrateOldMsgHotData(
            @RequestBody(required = false) MigrateOldMsgHotDataJob.Param param) {
        migrateOldMsgHotDataJob.tryExecute(param, true);
        return "submitted";
    }

    @PostMapping("/setImSendPriority")
    @EnableResponseAdvice(enable = false)
    public Object setImSendPriority(@RequestBody @Valid SetImSendPriorityRequest request) {
        return imService.setImSendPriority(request);
    }

    @PostMapping("/updateMnsChannelTemplate")
    @EnableResponseAdvice(enable = false)
    public Object updateMnsChannelTemplate(@RequestBody @Valid UpdateMnsChannelTemplateRequest request) {
        int size = messageTemplateManager.changeChannelTemplateCode(
                request.getChannelCode(), request.getSrcTemplateCode(), request.getDestTemplateCode());
        return String.format("updated templates: %d", size);
    }

    @PostMapping("/createMnsTemplate")
    @EnableResponseAdvice(enable = false)
    public String createMnsTemplate(@RequestBody CreateTemplateRequestDto request){
        platService.createTemplate(request);
        return "created";
    }

    @PostMapping("/sendSms")
    @EnableResponseAdvice(enable = false)
    public Object sendSms(@RequestBody @Valid SendMessageRequestDto request) {
        return mnsNoticesApi.sendMessage(request);
    }

    @PostMapping("/sendSmsCode")
    @EnableResponseAdvice(enable = false)
    public Object sendSmsCode(@RequestBody @Valid MnsSendCodeV2Req request) {
        return mnsNoticesApi.sendCodeV2(request);
    }

    @PostMapping("/addMnsChannel")
    @EnableResponseAdvice(enable = false)
    public Object addMnsChannel(@RequestBody @Valid AddMnsChannelRequest request){
        return messageChannelRouter.addChannel(request);
    }

    @PostMapping("/updateMnsTemplateContent")
    @EnableResponseAdvice(enable = false)
    public Object updateMnsTemplateContent(@RequestBody @Valid UpdateMnsTemplateContentRequest request) {
        return mnsMessageTemplateDao.lambdaUpdate()
                .eq(MNSMessageTemplate::getTemplateNo, request.getInnerTemplateCode())
                .set(MNSMessageTemplate::getTemplateContent, request.getTemplateContent())
                .update();
    }

    @PostMapping("/listMnsApps")
    @EnableResponseAdvice(enable = false)
    public Object listMnsApps(){
        return platService.listAllApps();
    }
}