package com.jeequan.jeepay.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.cache.RedisUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchStore;
import com.jeequan.jeepay.core.entity.PayOrderCount;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.QRCodeParams;
import com.jeequan.jeepay.core.model.oauth2.WxpayOauth2Params;
import com.jeequan.jeepay.db.entity.MchSubInfoEntity;
import com.jeequan.jeepay.db.entity.Route;
import com.jeequan.jeepay.db.entity.RouteManage;
import com.jeequan.jeepay.db.entity.RouteRecord;
import com.jeequan.jeepay.model.Condition;
import com.jeequan.jeepay.model.SeniorStrategy;
import com.jeequan.jeepay.service.mapper.MchStoreMapper;
import com.jeequan.jeepay.service.mapper.PayOrderMapper;
import com.jeequan.jeepay.service.mapper.RouteMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2024-04-19
 */
@Service
public class RouteService extends ServiceImpl<RouteMapper, Route>{

    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RouteManageService routeManageService;
    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private MchStoreMapper mchStoreMapper;
    /**
     * 新增路由
     * @param entity
     */
    public void addSave(Route entity) {
        entity.preCheck();
        Route route = getDefault(entity.getMchNo());
        if(route != null && CS.YES == entity.getIsDefault()){
            throw new BizException("默认的支付路由策略有且只有一个");
        }
        this.save(entity);
    }

    /**
     * 获取默认的路由策略
     * @return
     */
    public Route getDefault(String mchNo) {
        return baseMapper.getDefault(mchNo);
    }

    /**
     * 分页查询
     * @param page
     * @param entity
     * @return
     */
    public IPage<Route> pageList(Page<Route> page, Route entity) {
        Date[] dateRange = entity.buildQueryDateRange();
        return baseMapper.pageList(page,entity,dateRange);
    }

    /**
     * 删除
     * @param routeId
     */
    public void del(String routeId) {
        Long count = routeManageService.getByRouteCount(routeId);
        if(count > 0){
            throw new BizException("当前路由已经关联了门店信息，请先在路由策略管理中删除绑定的门店信息后在操作");
        }
        baseMapper.deleteById(routeId);
    }


    /**
     * 数据统计
     * @param entity
     * @return
     */
    public PayOrderCount totalCount(Route entity) {
        Date[] dateRange = entity.buildQueryDateRange();
        return baseMapper.totalCount(entity,dateRange);
    }

    /**
     * 获取二维码
     * @param routeId
     * @return
     */
    public String getQrCode(String routeId) {
        Route route = preCheck(routeId);
        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
        String tk = dbApplicationConfig.genQrToken(QRCodeParams.TYPE_ROUTE,route.getRouteId(),null);
        return dbApplicationConfig.getPaySiteUrl() + "/api/scan/imgs/" + tk + ".png";
    }

    public Route preCheck(String routeId) {
        Route route = getById(routeId);
        if(route == null){
            throw new BizException("路由策略规则数据异常");
        }
        if(CS.YES != route.getState()){
            throw new BizException("路由策略规则已被禁用");
        }
        return route;
    }

    /**
     * 执行路由操作
     * @param routeId
     * @param amt
     * @param payWayType 取值范围 WECHAT ALIPAY
     * @return
     */
    public RouteManage doRoute(String routeId, Long amt, String payWayType) {
        Route route = preCheck(routeId);
        List<RouteManage> list = routeManageService.listByRouteId(routeId,CS.YES);
        if(list.isEmpty()){
            throw new BizException("当前路由未绑定或未启用门店数据，请前往路由门店管理中绑定或启用");
        }
//        List<RouteManage> result = list.stream().filter(item -> CS.YES == item.getRouteState()).collect(Collectors.toList());
//        if(result.isEmpty()){
//            throw new BizException("当前路由策略，请前往路由门店管理中绑定或启用");
//        }
        LocalTime nowTime = LocalTime.parse(DateUtil.format(DateUtil.date(), "HH:mm"));
        List<RouteManage> result = list.stream().filter(item -> Long.valueOf(item.getAmtRange().get(0)) <= amt && Long.valueOf(item.getAmtRange().get(1)) >= amt)
                .filter(item -> item.getPayType().contains(payWayType))
                .filter(item -> nowTime.isAfter(LocalTime.parse(item.getTimeRange().get(0))) && nowTime.isBefore(LocalTime.parse(item.getTimeRange().get(1)))).collect(Collectors.toList());
        if(result.isEmpty()){
            throw new BizException("当前路由未获取符合的门店数据");
        }
        //匹配高级策略
        SeniorStrategy senior = route.getSeniorStrategy();
        //默认使用随机策略
        String type = senior == null ||  CS.YES == senior.getIsRouteType() ? SeniorStrategy.RANDOM : senior.getRouteTypeValue();
        if(senior != null){
            result = result.stream().filter(item -> {
                boolean isFiltered = true;
                if (CS.YES == senior.getIsPayType()) {
                    for (String exVal:senior.getPayTypeValue()) {
                        isFiltered = isFiltered && item.getPayType().contains(exVal);
                    }
                }
                if (CS.YES == senior.getIsSettleType()) {
                    for (String exVal:senior.getSettleTypeValue()) {
                        isFiltered = isFiltered && item.getSettleType().contains(exVal);
                    }
                }
                if (CS.YES == senior.getIsIfCode()) {
                    isFiltered = isFiltered && item.getIfCode().equals(senior.getIfCodeValue());
                }
                if (senior.getIsIsvNo() != null && CS.YES == senior.getIsIsvNo()) {
                    isFiltered = isFiltered && item.getIsvNo().equals(senior.getIsvNoValue());
                }
                return isFiltered;
            }).collect(Collectors.toList());
            //继续匹配其他策略 用户交易策略
//            Byte isTradeRule = senior.getIsTradeRule();
//            if(CS.YES == isTradeRule){
//                switch (senior.getTradeRuleValue()){
//                    case SeniorStrategy.PREV:
//                }
//            }
        }
        if(result.isEmpty()){
            throw new BizException("当前路由的高级规则配置未获取符合的门店数据");
        }
        RouteManage routeManage = null;
        if(SeniorStrategy.RANDOM.equals(type)){
            routeManage = result.get(RandomUtil.randomInt(result.size()));
        }else{
            int index = RedisUtil.hasKey(routeId) ? RedisUtil.getObject(routeId,Integer.class) : 0;
            if(index >= result.size() - 1){
                RedisUtil.set(routeId,0);
                routeManage = result.get(0);
            }else{
                RedisUtil.set(routeId,index + 1);
                routeManage = result.get(index + 1);
            }
        }
        String storeId = routeManage.getStoreId();
        String mchNo = routeManage.getMchNo();
        com.jeequan.jeepay.db.entity.MchStore mchStore = mchStoreMapper.selectById(routeManage.getStoreId());
        routeManage.setStoreName(mchStore.getStoreName());
        List<Condition> ruleCondition = route.getRuleStrategy().getConditionList();
        Date endTime = new Date();
        List<Condition> ruleResult = ruleCondition.stream().filter(item -> {
            Integer timeVal = item.getTimeVal();
            Date startTime = DateUtil.offsetMinute(endTime, -timeVal);
            PayOrderCount orderCount = payOrderMapper.routeDateCount(startTime, endTime, storeId, mchNo);
            Byte condition = item.getCondition();
            Long cVal = Condition.NUM.equals(item.getType()) ? orderCount.getTotalSuccNum() : Condition.AMOUNT.equals(item.getType()) ? orderCount.getTotalSuccAmt() : Condition.FAIL_NUM.equals(item.getType()) ? orderCount.getTotalFailNum() : orderCount.getSuccRate().longValue();
            String msg = Condition.NUM.equals(item.getType()) ? "成功交易笔数" : Condition.AMOUNT.equals(item.getType()) ? "成功交易金额" : Condition.FAIL_NUM.equals(item.getType()) ? "失败交易笔数" : "付款成功率";
            switch (condition) {
                //大于或等于
                case 1:
                    item.setContentText(msg + "大于或等于" + item.getValue().get(0) + "笔");
                    return cVal >= Integer.valueOf(item.getValue().get(0));
                //小于或等于
                case 2:
                    item.setContentText(msg + "小于或等于" + item.getValue().get(0) + "笔");
                    return cVal <= Integer.valueOf(item.getValue().get(0));
                //介于之间
                default:
                    item.setContentText(msg + "介于" + item.getValue().get(0) + "%" + item.getValue().get(1) + "%");
                    return cVal >= Integer.valueOf(item.getValue().get(0)) && cVal <= Integer.valueOf(item.getValue().get(1));
            }
        }).collect(Collectors.toList());
        String condition = "";
        String resultMsg = "";
        if(!ruleResult.isEmpty()){
            for (Condition item:ruleResult) {
                RouteManage upManage = new RouteManage();
                upManage.setStoreId(storeId);
                routeManage.setOpType(item.getOpType());
                condition = item.getContentText();
                switch (item.getOpType()){
                    //修改门店状态
                    case Condition.STORE_STATE:
                        String method = item.getMethod();
                        Byte state = Condition.OPEN.equals(method) ? CS.YES : Condition.CLOSE.equals(method) ? CS.NO : (byte)2;
                        resultMsg = Condition.OPEN.equals(method) ? "启用门店" : Condition.CLOSE.equals(method) ? "停用门店" : "不路由门店";
                        if(state == 2 || state == CS.NO){
                            upManage.setRouteState(CS.NO);
                        }
                        if(state == 1){
                            upManage.setRouteState(CS.YES);
                        }
                        upManage.setState(state);
                        routeManage.setIsSend(true);
                        upManage.setRemark(condition + ",触发结果："+ resultMsg);
                        routeManageService.updateById(upManage);
                        break;
                    case Condition.SEND_NOTIFY:
                        resultMsg = "发送通知";
                        upManage.setRemark(condition + ",触发结果：" + resultMsg);
                        routeManage.setIsSend(true);
                        routeManage.setSendVal(item.getOptValue());
                        routeManageService.updateById(upManage);
                        break;
                }
            }
        }
        RouteRecord routeRecord = new RouteRecord(routeManage,route.getName(),condition,resultMsg);
        routeManage.setRouteRecord(routeRecord);
        routeManage.setRoute(route);
        return routeManage;
    }

    /**
     * 更新保存
     * @param entity
     */
    public void updateSave(Route entity) {
        entity.preCheck();
        if(CS.YES == entity.getIsDefault()){
            Route ext = getDefault(entity.getMchNo());
            //如果已经有默认的策略了并且已有的策略和当前修改的策略不一致 则吧其他的策略全部改成非默认
            if(ext != null && !ext.getRouteId().equals(entity.getRouteId())){
                LambdaUpdateWrapper<Route> uWrapper = Wrappers.lambdaUpdate();
                uWrapper.set(Route::getIsDefault,CS.NO).eq(Route::getMchNo,entity.getMchNo());
                this.update(uWrapper);
            }
        }
        updateById(entity);
    }
}
