package com.rongwei.safecommon.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.rongwei.commonservice.serial.service.SysSerialNumberService;
import com.rongwei.commonservice.service.RedisService;
import com.rongwei.rwadmincommon.system.domain.SysOrganizationDo;
import com.rongwei.rwadmincommon.system.vo.SysOrganizationVo;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.rwcommon.vo.CriteriaQuery;
import com.rongwei.rwcommon.vo.generalsql.BatchSaveVo;
import com.rongwei.rwcommon.vo.generalsql.GeneralInsertVo;
import com.rongwei.rwcommonentity.commonservers.vo.SysNotifyAnnounceVo;
import com.rongwei.rwcommonentity.commonservers.vo.SysSerialVo;
import com.rongwei.safecommon.fegin.CXAdminFeginClient;
import com.rongwei.safecommon.fegin.CXCommonFeginClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.util.*;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.SaveConstans.*;

/**
 * CXCommonUtils class
 *
 * @author XH
 * @date 2023/12/15
 */
@Component
public class CXCommonUtils {
    private static final Logger log = LoggerFactory.getLogger(CXCommonUtils.class.getName());
    @Autowired
    private RedisService autoRedisService;
    @Autowired
    private CXCommonFeginClient autoCommonFeginClient;
    @Resource
    private CXAdminFeginClient autoAdminFeginClient;
    @Autowired
    private SysSerialNumberService autoSysSerialNumberService;

    private static SysSerialNumberService sysSerialNumberService;

    private static RedisService redisService;

    private static CXCommonFeginClient commonFeginClient;
    private static CXAdminFeginClient adminFeginClient;
    public static final String DEFAULT_NOTIFY_STATUS = "3";


    @PostConstruct
    public void info() {
        redisService = autoRedisService;
        commonFeginClient = autoCommonFeginClient;
        adminFeginClient = autoAdminFeginClient;
        sysSerialNumberService = autoSysSerialNumberService;
    }


    /**
     * 发送消息提醒
     *
     * @param title         消息提醒标题
     * @param content       消息提醒内容
     * @param remark        消息提醒备注
     * @param recipientIds  接收人ID
     * @param roption       目前存的是业务数据ID
     * @param notifyStatus  消息提醒类型
     * @param pushWebsocket 是否向webSocket推送消息
     */
    public static void sendNotify(String title, String content, String remark,
                                  List<String> recipientIds, String roption,
                                  String notifyStatus, boolean pushWebsocket) {
        sendNotify(SecurityUtil.getUUID(), null, title, content, remark, recipientIds, roption, notifyStatus, pushWebsocket);
    }

    /**
     * 发送消息提醒
     *
     * @param notifyId      消息提醒ID
     * @param tenantId      消息提醒公司信息
     * @param title         消息提醒标题
     * @param content       消息提醒内容
     * @param remark        消息提醒备注
     * @param recipientIds  接收人ID
     * @param roption       目前存的是业务数据ID
     * @param notifyStatus  消息提醒类型
     * @param pushWebsocket 是否向webSocket推送消息
     */
    public static void sendNotify(String notifyId, String tenantId, String title, String content, String remark,
                                  List<String> recipientIds, String roption,
                                  String notifyStatus, boolean pushWebsocket) {
        if (recipientIds == null || recipientIds.isEmpty()) {
            log.debug("接收人ID为空");
            return;
        }
        SysNotifyAnnounceVo sysNotifyAnnounceVo = new SysNotifyAnnounceVo();
        sysNotifyAnnounceVo.setId(notifyId);
        sysNotifyAnnounceVo.setSenderid("8672bf72ab274bec83052868ae336b38");
        sysNotifyAnnounceVo.setNotifytype(notifyStatus);
        sysNotifyAnnounceVo.setNotifystatus(DEFAULT_NOTIFY_STATUS);
        sysNotifyAnnounceVo.setNotifytitle(title);
        sysNotifyAnnounceVo.setNotifycontent(content.replace("null", " "));
        sysNotifyAnnounceVo.setRemark(remark);
        if (StringUtils.isNotBlank(tenantId)) {
            sysNotifyAnnounceVo.setTenantid(tenantId);
        }
        // 特殊处理
        if (StringUtils.isNotBlank(roption)) {
            sysNotifyAnnounceVo.setRoption(roption);
        }
        sysNotifyAnnounceVo.setUserid(recipientIds.stream().distinct().collect(Collectors.joining(",")));
        log.debug("开始通过fegin发送消息通知: {}", sysNotifyAnnounceVo);
        commonFeginClient.sendNotify(sysNotifyAnnounceVo);
        // 通过webSocket推送数据
        if (pushWebsocket) {
            //防止推送用户过多，导致调用接口报错，实行分流
            Lists.partition(recipientIds, 10).forEach(userIds -> {
                pushApp(title, content, userIds);
            });
        }
    }


    /**
     * 发送消息提醒
     *
     * @param title        消息提醒标题
     * @param content      消息提醒内容
     * @param remark       消息提醒备注
     * @param recipientIds 接收人ID
     * @param roption      目前存的是业务数据ID
     * @param notifyStatus 消息提醒类型
     */
    public static void sendNotify(String title, String content, String remark,
                                  List<String> recipientIds, String roption,
                                  String notifyStatus) {
        sendNotify(title, content, remark, recipientIds, roption, notifyStatus, true);
    }


    public static void pushApp(String title, String content, List<String> recipientIds) {
        if(recipientIds.size() <= 0){
            return;
        }
        BatchSaveVo batchSaveVo = new BatchSaveVo();
        LinkedList<GeneralInsertVo> generalInserts = new LinkedList<>();
        for (String recipientId : recipientIds) {
            String uuid = SecurityUtil.getUUID();

            Map<String, Object> map = new HashMap<>();
            map.put("ID",uuid);
            map.put("DELETED","0");
            map.put("CREATEDATE",DateUtil.now());
            map.put("TITLE", title);
            map.put("CONTENT", content);
            map.put("USERID", recipientId);

            GeneralInsertVo generalInsertVo = new GeneralInsertVo();
            generalInsertVo.setTablename("app_push_message");
            generalInsertVo.setInsertcolumns(map);
            generalInsertVo.setAutoGenId(false);
            generalInsertVo.setIdCol("ID");
            generalInserts.add(generalInsertVo);
        }
        batchSaveVo.setGeneralInserts(generalInserts);
        adminFeginClient.batchSaveList(batchSaveVo);

        //推送websocket消息给app
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("title", title);
        jsonObject.put("content", content);
        jsonObject.put("userIds", recipientIds);
        commonFeginClient.pushToWeb("app", jsonObject.toJSONString());
    }


    /**
     * 发送消息提醒
     *
     * @param id            主键id
     * @param title         消息提醒标题
     * @param content       消息提醒内容
     * @param remark        消息提醒备注
     * @param recipientIds  接收人ID
     * @param roption       目前存的是业务数据ID
     * @param notifyStatus  消息提醒类型
     * @param pushWebsocket 是否向webSocket推送消息
     */
    public static void sendNotify(String id, String title, String content, String remark,
                                  List<String> recipientIds, String roption,
                                  String notifyStatus, boolean pushWebsocket) {
        if (recipientIds == null || recipientIds.isEmpty()) {
            log.debug("接收人ID为空");
            return;
        }
        SysNotifyAnnounceVo sysNotifyAnnounceVo = new SysNotifyAnnounceVo();
        sysNotifyAnnounceVo.setId(id);
        sysNotifyAnnounceVo.setSenderid("8672bf72ab274bec83052868ae336b38");
        sysNotifyAnnounceVo.setNotifytype(notifyStatus);
        sysNotifyAnnounceVo.setNotifystatus(DEFAULT_NOTIFY_STATUS);
        sysNotifyAnnounceVo.setNotifytitle(title);
        sysNotifyAnnounceVo.setNotifycontent(content.replace("null", " "));
        sysNotifyAnnounceVo.setRemark(remark);
        // 特殊处理
        if (StringUtils.isNotBlank(roption)) {
            sysNotifyAnnounceVo.setRoption(roption);
        }
        sysNotifyAnnounceVo.setUserid(recipientIds.stream().distinct().collect(Collectors.joining(",")));
        log.debug("开始通过fegin发送消息通知: {}", sysNotifyAnnounceVo);
        commonFeginClient.sendNotify(sysNotifyAnnounceVo);
        // 通过webSocket推送数据
        if (pushWebsocket) {
            //防止推送用户过多，导致调用接口报错，实行分流
            Lists.partition(recipientIds, 10).forEach(userIds -> {
                pushApp(title, content, userIds);
            });
        }
    }


    /**
     * 流水码生成
     *
     * @param moduleCode      流水码CODE
     * @param ruleTemplateStr 流水码编码规则
     * @param tenantId        租户id
     * @return
     */
    public static String streamCodeGeneration(String moduleCode, String ruleTemplateStr, String tenantId) {
        String orgCode = ORG_CODE_MAP.getOrDefault(tenantId, "");
        log.info("开始生成流水码");
        SysSerialVo sysSerialVo = new SysSerialVo();
        sysSerialVo.setModulecode(String.format("%s_%s", moduleCode, orgCode));
        sysSerialVo.setRuleTemplateStr(String.format("%s-%s", orgCode, ruleTemplateStr));
        String streamCode = sysSerialNumberService.getCodeByTemplate(sysSerialVo);
        log.info("流水码生成成功：{}", streamCode);
        return streamCode;
    }

    /**
     * 流水码生成
     *
     * @param moduleCode      流水码CODE
     * @param ruleTemplateStr 流水码编码规则
     * @param tenantId        租户id
     * @return
     */
    public static String streamCodeGeneration(String moduleCode, String ruleTemplateStr, String resetRule, String tenantId) {

        String orgCode = (moduleCode.contains("_aq") ? AQ_ORG_CODE_MAP : ORG_CODE_MAP).getOrDefault(tenantId, "");
        log.info("开始生成流水码");
        SysSerialVo sysSerialVo = new SysSerialVo();
        sysSerialVo.setModulecode(String.format("%s_%s", moduleCode, orgCode));
        sysSerialVo.setRuleTemplateStr(String.format("%s-%s", orgCode, ruleTemplateStr));
        sysSerialVo.setResetrule(resetRule);
        String streamCode = sysSerialNumberService.getCodeByTemplate(sysSerialVo);
        log.info("流水码生成成功：{}", streamCode);
        return streamCode;
    }


    public static SysUserVo getCurrentUser() {
        // 获取当前登录人信息
        SysUserVo currUser = null;
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            if (request != null) {
                String token = request.getHeader("token");
                if (com.rongwei.rwcommon.utils.StringUtils.isNotEmpty(token)) {
                    currUser = redisService.getLoginUser(token);
                }
            }
        }
        return currUser;
    }
    public static String getCurrentUserFactoryId(SysUserVo currentUser) {
        if(currentUser==null){
            currentUser   = getCurrentUser();
        }
        List<SysOrganizationVo> organizationDoList = currentUser.getOrganizationDoList();
        String factoryId = organizationDoList.stream()
                .filter(org -> MINUS_ONE.equals(org.getPid()))
                .map(SysOrganizationDo::getId)
                .distinct()
                .collect(Collectors.joining(","));
        if (StringUtils.isBlank(factoryId)) {
            factoryId = organizationDoList.stream().map(info -> info.getFullpid().split(",")[1]).distinct().collect(Collectors.joining(","));
        }
        return factoryId;
    }

    /**
     * 计算时间和当前时间相差几天
     *
     * @param startDate
     * @return
     */
    public static long aFewDaysApart(Date startDate) {
        Calendar startInstance = Calendar.getInstance();
        startInstance.setTime(startDate);
        LocalDate startLocalDate = LocalDate.of(startInstance.get(Calendar.YEAR), startInstance.get(Calendar.MONTH) + 1, startInstance.get(Calendar.DAY_OF_MONTH));
        return startLocalDate.toEpochDay() - LocalDate.now().toEpochDay();
    }


    /**
     * 删除消息提醒
     *
     * @param notifyType
     * @param roption
     * @return
     * @date 2024/1/29 17:12
     * @author shangmi
     */

    public static void deleteSendNotify(String notifyType, String roption) {
        JSONArray data = JSONUtil.parseArray(commonFeginClient.list(new HashMap<String, Object>() {{
            this.put("NOTIFYTYPE", notifyType);
            if (roption != null) {
                this.put("ROPTION", roption);
            }
        }}).getData());

        if (!data.isEmpty()) {
            List<String> ids = data.stream().map(info -> JSONUtil.parseObj(info).get("id").toString()).collect(Collectors.toList());
            commonFeginClient.delete(ids);
        }
    }

    public static R upload(MultipartFile file, String relationid) {
        return commonFeginClient.upload(file, relationid);
    }

    /**
     * 参数校验
     *
     * @param booleanSupplier
     * @param returnMsg
     * @param errorMsg
     * @param errorMsgParameter
     */
    public static void parameterCheck(BooleanSupplier booleanSupplier, String returnMsg, String errorMsg, Object... errorMsgParameter) {
        if (booleanSupplier.getAsBoolean()) {
            log.error(errorMsg, errorMsgParameter);
            if (org.apache.commons.lang.StringUtils.isNotBlank(returnMsg)) {
                throw new RuntimeException(returnMsg);
            }
        }
    }
}
