package cn.lihongjie.coal.dingtalkBot.service;

import cn.hutool.http.HttpUtil;
import cn.lihongjie.coal.base.dto.CommonQuery;
import cn.lihongjie.coal.base.dto.IdRequest;
import cn.lihongjie.coal.base.service.BaseService;
import cn.lihongjie.coal.common.FreeMakerUtils;
import cn.lihongjie.coal.dbFunctions.DbFunctionService;
import cn.lihongjie.coal.dingtalkBot.dto.*;
import cn.lihongjie.coal.dingtalkBot.entity.DingtalkBotEntity;
import cn.lihongjie.coal.dingtalkBot.mapper.DingtalkBotMapper;
import cn.lihongjie.coal.dingtalkBot.repository.DingtalkBotRepository;
import cn.lihongjie.coal.dingtalkBotScene.entity.DingtalkBotSceneEntity;
import cn.lihongjie.coal.dingtalkBotScene.service.DingtalkBotSceneService;
import cn.lihongjie.coal.dingtalkBotTemplate.entity.DingtalkBotTemplateEntity;
import cn.lihongjie.coal.dingtalkBotTemplate.service.DingtalkBotTemplateService;
import cn.lihongjie.coal.exception.BizException;

import com.fasterxml.jackson.databind.ObjectMapper;

import freemarker.core.InvalidReferenceException;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@Transactional
public class DingtalkBotService extends BaseService<DingtalkBotEntity, DingtalkBotRepository> {
    @Autowired DingtalkBotTemplateService dingtalkBotTemplateService;
    @Autowired ObjectMapper objectMapper;
    @Autowired private DingtalkBotRepository repository;
    @Autowired private DingtalkBotMapper mapper;
    @Autowired private ConversionService conversionService;
    @Autowired private DbFunctionService dbFunctionService;

    public DingtalkBotDto create(CreateDingtalkBotDto request) {
        DingtalkBotEntity entity = mapper.toEntity(request);

        this.repository.save(entity);
        return getById(entity.getId());
    }

    public DingtalkBotDto update(UpdateDingtalkBotDto request) {
        DingtalkBotEntity entity = this.repository.get(request.getId());
        this.mapper.updateEntity(entity, request);

        this.repository.save(entity);

        return getById(entity.getId());
    }

    public void delete(IdRequest request) {
        boolean linked = this.repository.isLinked(request.getIds());

        if (linked) {
            throw new BizException("数据已被关联，无法删除");
        }

        this.repository.deleteAllById(request.getIds());
    }

    public DingtalkBotDto getById(String id) {
        DingtalkBotEntity entity = repository.get(id);

        return mapper.toDto(entity);
    }

    public Page<DingtalkBotDto> list(CommonQuery query) {
        Page<DingtalkBotEntity> page =
                repository.findAll(
                        query.specification(conversionService),
                        PageRequest.of(
                                query.getPageNo(),
                                query.getPageSize(),
                                Sort.by(query.getOrders())));

        return page.map(this.mapper::toDto);
    }

    @Autowired DingtalkBotSceneService dingtalkBotSceneService;

    public SendMsgResponse send(SendMsgRequest request) {

        SendMsgResponse response = new SendMsgResponse();
        ArrayList<SendMsgResult> results = new ArrayList<>();
        response.setResults(results);
        List<DingtalkBotEntity> botList;
        DingtalkBotTemplateEntity template;
        if (StringUtils.isNotEmpty(request.getSceneCode())) {

            DingtalkBotSceneEntity scene =
                    dingtalkBotSceneService.getByCode(
                            request.getOrganizationId(), request.getSceneCode());

            botList = scene.getDingtalkBots();
            template = scene.getDingtalkBotTemplate();
        } else {

            botList = this.repository.findAllById(request.getDingtalkBotIds());
            template = dingtalkBotTemplateService.get(request.getDingtalkBotTemplateId());
        }

        if (MapUtils.isNotEmpty(request.getParams())) {

            for (DingtalkBotEntity dingtalkBotEntity : botList) {
                results.add(doSend(dingtalkBotEntity, template, request.getParams()));
            }
        }

        if (CollectionUtils.isNotEmpty(request.getParamsList())) {

            for (DingtalkBotEntity dingtalkBotEntity : botList) {

                for (Map<String, Object> params : request.getParamsList()) {

                    results.add(doSend(dingtalkBotEntity, template, params));
                }
            }
        }
        return response;
    }

    @SneakyThrows
    private SendMsgResult doSend(
            DingtalkBotEntity dingtalkBotEntity,
            DingtalkBotTemplateEntity dingtalkBotTemplateEntity,
            Map<String, Object> params) {

        SendMsgResult sendMsgResult = new SendMsgResult();

        sendMsgResult.setBot(mapper.toDto(dingtalkBotEntity));
        HashMap<Object, Object> body = new HashMap<>();

        body.put("msgtype", "markdown");

        try {
            String content = FreeMakerUtils.render(dingtalkBotTemplateEntity.getTemplate(), params);

            String title = FreeMakerUtils.render(dingtalkBotTemplateEntity.getTitle(), params);

            body.put(
                    "markdown",
                    new HashMap<String, Object>() {
                        {
                            put("title", title);

                            put("text", content);
                        }
                    });

        } catch (Exception referenceException) {

            if (referenceException instanceof InvalidReferenceException ee) {

                log.info(
                        "模板渲染失败, 模板: {} 参数: {} 表达式：{}",
                        dingtalkBotTemplateEntity,
                        params,
                        ee.getBlamedExpressionString(),
                        referenceException);

                throw new BizException("模板渲染失败, 请检查模板参数是否正确 " + ee.getBlamedExpressionString());
            } else {
                throw referenceException;
            }
        }
        try {

            String postBody = objectMapper.writeValueAsString(body);
            String response = HttpUtil.post(dingtalkBotEntity.getUrl(), postBody);

            log.info("发送钉钉消息成功, 请求: {} 返回结果: {} ", postBody, response);

            sendMsgResult.setResponse(response);

        } catch (Exception e) {
            log.error("发送钉钉消息失败", e);

            sendMsgResult.setStackTrace(e.getMessage());
        }
        return sendMsgResult;
    }
}
