package com.gree.mall.manager.logic.common;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.AdminCompanyWechatService;
import com.gree.mall.manager.plus.service.AdminUserService;
import com.gree.mall.manager.plus.service.NoticeParamService;
import com.gree.mall.manager.plus.service.UserService;
import com.gree.mall.manager.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 微信公众号通知
 */
@Slf4j
@Component
public class WxPubNoticeLogic {

    @Autowired
    RedisUtil redisUtil;
    @Autowired
    WechatLogic wechatLogic;
    @Autowired
    NoticeParamService noticeParamService;
    @Autowired
    AdminCompanyWechatService adminCompanyWechatService;
    @Autowired
    UserService userService;
    @Autowired
    AdminUserService adminUserService;
    @Value("${spring.profiles.active}")
    private String env;
    @Value("${wechat.mp.url}")
    private String mpUrl;


    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");


    final Integer[] errMin = {1,2,5,10,20,40,80,160,320};
    final Integer errNum = errMin.length;

    public User getUserByMobile(String mobile,String companyWechatId){
        if(StringUtils.isBlank(mobile)){
            return null;
        }
        User user = userService.lambdaQuery()
                .ne(User::getMpOpenId,"")
                .eq(User::getMobile, mobile)
                .eq(User::getCompanyWechatId, companyWechatId).one();
        return user;
    }

    /**
     * 消息模板thing类型字段处理，只能20个字内
     * @param value
     * @return
     */
    public String getThing(String value){
        if(StringUtils.isBlank(value)){
            return "";
        }
        value = value.length() > 20 ? value.substring(0,18)+".." : value;
        return value;
    }

    public String getPhrase(String value){
        if(StringUtils.isBlank(value)){
            return "";
        }
        value = value.length() > 4 ? value.substring(0,4) : value;
        return value;
    }

    /**
     * 所有需要通知的商户账号
     * @param companyWechatId
     * @return
     */
    public List<AdminUser> getAdminUserList(String companyWechatId){
        List<AdminUser> list = adminUserService.lambdaQuery()
                .eq(AdminUser::getCompanyWechatId, companyWechatId)
                .eq(AdminUser::getPubNotice, true)
                .ne(AdminUser::getLinkPhone,"")
                .list();
        return list;
    }

    /**
     * 工单派工，改派通知 - 通知对象：师傅
     * @param orderType 工单类型
     * @param orderBaseId 工单号
     * @param time 预约时间,预约时间为空则传派工时间
     * @param content 需求名称 例如：格力家用空调x3
     * @param address 派单地址
     */
    public void addDispatch(String mobile,String companyWechatId,String orderType,String orderBaseId,Date time,String content,String address){
        try {
            if (StringUtils.isBlank(mobile) || StringUtils.isBlank(companyWechatId)) {
                return;
            }
            User user = getUserByMobile(mobile, companyWechatId);
            if (user == null || StringUtils.isBlank(user.getMpOpenId())) {
                return;
            }
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
            String templateId = adminCompanyWechat.getPubTemplateId1();

            Map<String, String> map = new HashMap<>();
            map.put("short_thing2", orderType);//工单类型
            map.put("character_string6", orderBaseId);//工单编号
            map.put("time4", sdf.format(time));//派工时间
            map.put("phrase8", getPhrase(content));//需求名称
            map.put("thing16", getThing(address));//服务地址

            NoticeParam bean = new NoticeParam();
            bean.setMobile(mobile);
            bean.setMpOpenId(user.getMpOpenId());
            bean.setTitle("工单派工，改派通知");
            bean.setTemplateId(templateId);
            bean.setContent(JSONObject.toJSONString(map));
            bean.setPagePath("packageWorkorder/pages/orderDetail?id="+orderBaseId);//小程序跳转地址，没就空着
            bean.setSubAppId(adminCompanyWechat.getSubAppId());
            bean.setCompanyWechatId(adminCompanyWechat.getCompanyWechatId());
            bean.setCompanyWechatName(adminCompanyWechat.getCompanyName());
            bean.insert();
        }catch(Exception e){
            log.error("【添加工单派工，改派通知失败】",e);
        }
    }

    /**
     * 抢单通知
     * @param users
     * @param pgOrderBases
     */
    public void addDispatchBatch(List<User> users, List<PgOrderBase> pgOrderBases){
        try {
            if (CollectionUtils.isEmpty(users) || CollectionUtils.isEmpty(pgOrderBases)) {
                return;
            }
            String companyWechatId = pgOrderBases.get(0).getCompanyWechatId();
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
            String templateId = adminCompanyWechat.getPubTemplateId7();

            List<NoticeParam> noticeParams = new ArrayList<>();

            for(PgOrderBase pgOrderBase : pgOrderBases) {
                Map<String, String> map = new HashMap<>();
                map.put("thing10", getThing("待抢单:"+pgOrderBase.getOrderTitle()));//服务类目
                map.put("time4", sdf.format(new Date()));//派工时间
                map.put("thing14", getThing(pgOrderBase.getUserName()));//服务客户
                map.put("thing16", getThing(pgOrderBase.getProvince()+pgOrderBase.getCity()+pgOrderBase.getArea()+pgOrderBase.getStreet()));//服务地址

                for (User user : users) {
                    NoticeParam bean = new NoticeParam();
                    bean.setMobile(user.getMobile());
                    bean.setMpOpenId(user.getMpOpenId());
                    bean.setTitle("抢单通知");
                    bean.setTemplateId(templateId);
                    bean.setContent(JSONObject.toJSONString(map));
                    bean.setPagePath("packageWorkorder/pages/orderDetail?behavior=lqdd&id=" + pgOrderBase.getId());//小程序跳转地址，没就空着
                    bean.setSubAppId(adminCompanyWechat.getSubAppId());
                    bean.setCompanyWechatId(adminCompanyWechat.getCompanyWechatId());
                    bean.setCompanyWechatName(adminCompanyWechat.getCompanyName());
                    noticeParams.add(bean);
                }
            }
            noticeParamService.saveBatch(noticeParams);
        }catch(Exception e){
            log.error("【添加抢单通知失败】",e);
        }
    }


    /**
     * 报修申请审批通知
     * @param mobile
     * @param companyWechatId
     * @param username 师傅名称+电话
     * @param time 报修时间
     * @param type 项目名称
     * @param content 收费项目或配件*数量，总金额
     * @param orderBaseId 申请状态 + 单号
     */
    public void addWbAmountApply(String mobile, String companyWechatId, String username, Date time, String type,String content,String orderBaseId,String applyId){
        if(StringUtils.isBlank(mobile) || StringUtils.isBlank(companyWechatId)){
            return;
        }
        try{
            User user = getUserByMobile(mobile, companyWechatId);
            if(user == null || StringUtils.isBlank(user.getMpOpenId())){
                return;
            }
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
            String templateId = adminCompanyWechat.getPubTemplateId5();
            Map<String, String> map = new HashMap<>();
            map.put("thing2", getThing(username));
            map.put("time10",sdf.format(time));
            map.put("thing4",getThing(type));
            map.put("thing5",getThing(content));
            map.put("character_string8", orderBaseId);

            NoticeParam bean = new NoticeParam();
            bean.setMobile(mobile);
            bean.setMpOpenId(user.getMpOpenId());
            bean.setTitle("报修申请审批通知");
            bean.setTemplateId(templateId);
            bean.setContent(JSONObject.toJSONString(map));
            bean.setPagePath("packageHome/pages/maintenance/applyDetail?id="+applyId);//小程序跳转地址，没就空着
            bean.setSubAppId(adminCompanyWechat.getSubAppId());
            bean.setCompanyWechatId(adminCompanyWechat.getCompanyWechatId());
            bean.setCompanyWechatName(adminCompanyWechat.getCompanyName());
            bean.insert();
        }catch(Exception e){
            log.error("【添加报修申请审批通知失败】",e);
        }
    }


    /**
     * 结算费用发放通知
     * @param mobile 师傅手机号
     * @param companyWechatId 商户id
     * @param goodsName 例如：2024-02月份安维费用发放
     * @param workerName 师傅名称
     * @param amount 发放金额
     * @param payTime 发放时间
     * @param websitName 网点名称
     */
    public void addSettleNotice(String mobile, String companyWechatId, String goodsName,String workerName,BigDecimal amount,Date payTime,String websitName){
        if(StringUtils.isBlank(mobile) || StringUtils.isBlank(companyWechatId)){
            return;
        }
        try{
            User user = getUserByMobile(mobile, companyWechatId);
            if(user == null || StringUtils.isBlank(user.getMpOpenId())){
                return;
            }
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
            String templateId = adminCompanyWechat.getPubTemplateId6();
            Map<String, String> map = new HashMap<>();
            map.put("thing3", getThing(goodsName));
            map.put("phrase18",getPhrase(workerName));
            map.put("amount5",amount+"");
            map.put("time26",sdf.format(payTime));
            map.put("thing29", getThing(websitName));

            NoticeParam bean = new NoticeParam();
            bean.setMobile(mobile);
            bean.setMpOpenId(user.getMpOpenId());
            bean.setTitle("结算费用发放通知");
            bean.setTemplateId(templateId);
            bean.setContent(JSONObject.toJSONString(map));
            //todo 缺安维费用页面
            //bean.setPagePath("packageHome/pages/maintenance/applyDetail?id="+applyId);//小程序跳转地址，没就空着
            bean.setSubAppId(adminCompanyWechat.getSubAppId());
            bean.setCompanyWechatId(adminCompanyWechat.getCompanyWechatId());
            bean.setCompanyWechatName(adminCompanyWechat.getCompanyName());
            bean.insert();
        }catch(Exception e){
            log.error("【添加结算费用发放通知失败】",e);
        }
    }

    /**
     * 配件取货通知
     * @param mobile 师傅手机号
     * @param companyWechatId 商户id
     * @param orderBaseId 订单编号
     * @param goodsName 商品名称（配件1名称x数量+配件2名称x数量）
     * @param linkPhone 联系方式
     * @param websitName 门店名称
     * @param address 门店地址
     * @param websitName 网点名称
     */
    public void takePartsNotice(String mobile, String companyWechatId, String orderBaseId, String goodsName, String linkPhone, String websitName, String address){
        if(StringUtils.isBlank(mobile) || StringUtils.isBlank(companyWechatId)){
            return;
        }
        try{
            User user = getUserByMobile(mobile, companyWechatId);
            if(user == null || StringUtils.isBlank(user.getMpOpenId())){
                return;
            }
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
            String templateId = adminCompanyWechat.getPubTemplateId8();
            Map<String, String> map = new HashMap<>();
            map.put("character_string2", orderBaseId);
            map.put("thing8", getThing(goodsName));
            map.put("phone_number6", linkPhone);
            map.put("thing11", websitName);
            map.put("thing5", getThing(address));

            NoticeParam bean = new NoticeParam();
            bean.setMobile(mobile);
            bean.setMpOpenId(user.getMpOpenId());
            bean.setTitle("取货通知");
            bean.setTemplateId(templateId);
            bean.setContent(JSONObject.toJSONString(map));
            bean.setPagePath("packageMaterial/pages/partsApply/list?tab=END");//小程序跳转地址，没就空着
            bean.setSubAppId(adminCompanyWechat.getSubAppId());
            bean.setCompanyWechatId(adminCompanyWechat.getCompanyWechatId());
            bean.setCompanyWechatName(adminCompanyWechat.getCompanyName());
            bean.insert();
        }catch(Exception e){
            log.error("【取货通知失败】",e);
        }
    }


    public void push(){
        //只查询昨晚20点到今天的
        DateTime dateTime = DateUtil.offsetDay(DateUtil.beginOfDay(new Date()), -1);
        DateTime startTime = DateUtil.offsetHour(dateTime, 20);
        List<NoticeParam> list = noticeParamService.lambdaQuery()
                .eq(NoticeParam::getStatus, false)
                .le(NoticeParam::getErrNum, errNum)
                .ge(NoticeParam::getCreateTime, DateUtil.formatDateTime(startTime))
                .list();

        if(list.isEmpty()){
            return;
        }
        for(NoticeParam noticeParam : list) {
            this.push(noticeParam);
        }
    }

    /**
     * 新版通知v2-发送通知
     */
    public void push(NoticeParam bean){
        //判断有失败的情况间隔的时间达到要求没
        if(bean.getErrNum() >= errNum)
            return;
        if(bean.getErrNum() > 0) {
            Integer min = errMin[bean.getErrNum() - 1];
            DateTime newLastTime = DateUtil.offsetMinute(bean.getLastTime(), min);
            if(newLastTime.getTime() > new Date().getTime())
                return;
        }
        HashMap hashMap = JSONObject.parseObject(bean.getContent(), HashMap.class);
        List<WxMpTemplateData> data = supplyV2(hashMap);
        Boolean push = this.push(bean.getMpOpenId(), bean.getTemplateId(), data, bean.getPagePath(),bean.getSubAppId(),bean.getCompanyWechatId());
        if(push){
            bean.setStatus(true);
        }else{
            bean.setErrNum(bean.getErrNum() + 1);
        }
        bean.setLastTime(new Date());
        bean.updateById();
    }



    public List<WxMpTemplateData> supplyV2(Map<String,String> map){
        List<WxMpTemplateData> data = Lists.newArrayList();
        for (String s : map.keySet()) {
            WxMpTemplateData keyword0 = new WxMpTemplateData(s,map.get(s));
            data.add(keyword0);
        }
        return data;
    }


    /**
     * 推送公众号模板通知
     * @param openId 公众号的模板id
     * @param data 模板内容
     * @param pagepath 跳转小程序路径
     */
    private Boolean push(String openId, String templateId, List<WxMpTemplateData> data, String pagepath,String subAppId,String companyWechatId){
//        if(!env.equals("prd")){
//            return true;
//        }
        WxMpService mpService = wechatLogic.getMpService(companyWechatId);
        WxMpTemplateMsgService templateMsgService = mpService.getTemplateMsgService();

        WxMpTemplateMessage templateMessage = new WxMpTemplateMessage();
        templateMessage.setToUser(openId);
        templateMessage.setTemplateId(templateId);
        templateMessage.setData(data);
        if(StringUtils.indexOf(pagepath,"?") > -1){
            pagepath += "&appid="+subAppId;
        }else{
            pagepath += "?appid="+subAppId;
        }
        templateMessage.setUrl(mpUrl + pagepath);

//        if(StringUtils.isEmpty(pagepath)){
//            pagepath = "pages/mine/workOrder/list";
//        }
        //if(env.equals("prd")) {
//            WxMpTemplateMessage.MiniProgram miniProgram = new WxMpTemplateMessage.MiniProgram(subAppId, pagepath, false);
//            templateMessage.setMiniProgram(miniProgram);
//        //}
//        log.info("【公众号通知跳转配置】:{},{}", JSONObject.toJSONString(templateMessage.getMiniProgram()), JSONObject.toJSONString(data));
        try {

            templateMsgService.sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            log.error("模板消息推送失败", e);
            return false;
        }
        return true;
    }



}
