package cn.iocoder.yudao.module.rescue.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.rescue.domain.*;
import cn.iocoder.yudao.module.rescue.utils.DateUtils;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.rescue.service.*;
import cn.iocoder.yudao.module.rescue.utils.pay.AesUtil;
import cn.iocoder.yudao.util.WechatPayConfig;
import cn.iocoder.yudao.util.WechatPayRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.iocoder.yudao.module.rescue.mapper.RescueOrderInfoMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.module.rescue.service.impl.RescueDriverInfoServiceImpl.getRandomString6;


/**
 * 救援订单Service业务层处理
 *
 * @author zcy
 * @date 2023-09-19
 */
@Service
public class RescueOrderInfoServiceImpl extends ServiceImpl<RescueOrderInfoMapper, RescueOrderInfo> implements IRescueOrderInfoService
{
    @Autowired
    private IRescueOrderDetailService orderDetailService;
    @Resource
    private WechatPayConfig wechatPayConfig;

    @Resource
    private WechatPayRequest wechatPayRequest;
    @Autowired
    private IRescueInfoService rescueInfoService;
    @Autowired
    private IDriverInfoService driverInfoService;
    @Autowired
    private AdminUserApi userService;
    @Autowired
    private IRescueInfoDetailService detailService;


    /**
     * 查询救援订单
     *
     * @param id 救援订单主键
     * @return 救援订单
     */
    @Override
    public RescueOrderInfo selectRescueOrderInfoById(Long id)
    {
        return baseMapper.selectRescueOrderInfoById(id);
    }

    /**
     * 查询救援订单列表
     *
     * @param rescueOrderInfo 救援订单
     * @return 救援订单
     */
    @Override
    public List<RescueOrderInfo> selectRescueOrderInfoList(RescueOrderInfo rescueOrderInfo)
    {
        return baseMapper.selectRescueOrderInfoList(rescueOrderInfo);
    }

    /**
     * 新增救援订单
     *
     * @param rescueOrderInfo 救援订单
     * @return 结果
     */
    @Override
    public int insertRescueOrderInfo(RescueOrderInfo rescueOrderInfo)
    {
        int insert = baseMapper.insert(rescueOrderInfo);
        RescueOrderDetail detail =new RescueOrderDetail();
        detail.setRescueOrderId(rescueOrderInfo.getId());
        detail.setRecordMoney(0l);
        detail.setRecordTime(new Date());
        detail.setRecordType("1");
        detail.setRescueDetailInfo("救援订单开始");
        orderDetailService.save(detail);
        return insert;
    }

    /**
     * 修改救援订单
     *
     * @param rescueOrderInfo 救援订单
     * @return 结果
     */
    @Override
    public int updateRescueOrderInfo(RescueOrderInfo rescueOrderInfo)
    {
        return baseMapper.updateById(rescueOrderInfo);
    }

    /**
     * 批量删除救援订单
     *
     * @param ids 需要删除的救援订单主键
     * @return 结果
     */
    @Override
    public int deleteRescueOrderInfoByIds(Long[] ids)
    {
        return baseMapper.deleteBatchIds(CollectionUtil.toList(ids));
    }

    /**
     * 删除救援订单信息
     *
     * @param id 救援订单主键
     * @return 结果
     */
    @Override
    public int deleteRescueOrderInfoById(Long id)
    {
        return baseMapper.deleteById(id);
    }

    @Override
    public Map<String,Object> createOrder(RescueInfo rescueInfo) throws Exception {
        LambdaQueryWrapper<RescueOrderInfo> queryWrapper =new LambdaQueryWrapper<>();
        queryWrapper.eq(RescueOrderInfo::getRescueInfoId,rescueInfo.getId());
        RescueOrderInfo orderInfo = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(orderInfo.getSetMoney())){
            throw new Exception("请先设置收款金额");
        }
        if (ObjectUtils.isNotEmpty(orderInfo.getPayTime())){
            throw new Exception("已收过款");
        }
//        if (StringUtils.isNotEmpty(orderInfo.getOrderNo())){
//            String resStr = wechatPayRequest.wechatHttpGet("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/"+orderInfo.getOrderNo()+"?mchid="+wechatPayConfig.getMchId());
//            JSONObject payRes = JSONObject.parseObject(resStr);
//            if (payRes.getString("trade_state").equals("SUCCESS")){
//                //代表实际支付成功了
//                throw new Exception("已收过款,请刷新订单");
//
//            }
//        }
        //待支付的情况下进行主动查询
        orderInfo.setOrderNo("appJy" + "-" + System.currentTimeMillis() + "-" + getRandomString6() + "-" + rescueInfo.getId());
        this.updateById(orderInfo);
        RescueOrderDetail rescueOrderDetail =new RescueOrderDetail();
        rescueOrderDetail.setRecordTime(new Date());
        rescueOrderDetail.setRecordMoney(orderInfo.getSetMoney());
        rescueOrderDetail.setRecordType("1");
        rescueOrderDetail.setRescueOrderId(orderInfo.getId());
        rescueOrderDetail.setRescueDetailInfo("司机发起收款");
        orderDetailService.save(rescueOrderDetail);
        return this.transactions(orderInfo.getId());
    }

    @Override
    public RescueOrderInfo getOrderByOrderNo(String orderNo) {
        LambdaQueryWrapper<RescueOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RescueOrderInfo::getOrderNo, orderNo);
        RescueOrderInfo one = this.getOne(queryWrapper);
        return one;
    }

    /**
     * 通过rescue_info_id去拿订单
     * @author 小李
     * @date 10:56 2024/8/27
     * @param rescueInfoId
    **/
    private RescueOrderInfo getOrderByRescueInfoId(Integer rescueInfoId){
        /*
        不确定是否会出现多条记录的情况，所以用创建订单时的时间降序去取最新的一条
         */
        List<RescueOrderInfo> list = this.list(new LambdaQueryWrapper<RescueOrderInfo>().eq(RescueOrderInfo::getRescueInfoId, rescueInfoId));
        // 没查到直接抛异常，理论上讲是不会抛的，但以防万一，抛了好过直接报错
        if (ObjectUtils.isEmpty(list) || CollectionUtil.isEmpty(list)){
            throw exception0(500, "系统故障");
        }
        // 如果只有一条，就用这一条
        if (list.size() == 1){
            return list.get(0);
        }
        // 多条就创建时间降序排序取第一条
        List<RescueOrderInfo> result = list.stream().sorted(Comparator.comparing(RescueOrderInfo::getCreateTime).reversed()).collect(Collectors.toList());
        return result.get(0);
    }


    public Map<String,Object> transactions(Long orderId){
        RescueOrderInfo orderInfo = this.getById(orderId);
        // 统一参数封装
        Map<String, Object> params = new HashMap<>(8);
        params.put("appid", wechatPayConfig.getAppId());
        params.put("mchid", wechatPayConfig.getMchId());
        params.put("description", "道路救援收费");
        params.put("out_trade_no", orderInfo.getOrderNo());
        params.put("notify_url", wechatPayConfig.getNotifyUrl());
        Map<String, Object> amountMap = new HashMap<>(4);
        // 金额单位为分
        amountMap.put("total", orderInfo.getSetMoney());
        //人民币
        amountMap.put("currency", "CNY");
        params.put("amount", amountMap);
        String paramsStr = JSON.toJSONString(params);
        String resStr = wechatPayRequest.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native",paramsStr);
        Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>(){});
        return resMap;
    }


    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public Map<String, String> payNotify(JSONObject jsonObject) {
        try {
            String key = wechatPayConfig.getApiV3Key();
            String json = jsonObject.toString();
            String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
            String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
            String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");

            String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
            //验签成功
            JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
            if(lock.tryLock()) {
                try {
                    // 解密resource中的通知数据 TODO
                    String orderNo = decryptDataObj.get("out_trade_no").toString();
                    String rescueInfoId = orderNo.split("-")[orderNo.split("-").length - 1];
                    RescueOrderInfo orderInfo = getOrderByRescueInfoId(Integer.parseInt(rescueInfoId));
                    if (orderInfo.getOrderStatus().equals("1")){
                        RescueInfo rescueInfo = rescueInfoService.getById(orderInfo.getRescueInfoId());
                        DriverInfo driverInfo = driverInfoService.getById(rescueInfo.getDriverId());
                        orderInfo.setPayTime(new Date());
                        orderInfo.setPayMoney(orderInfo.getSetMoney());
                        orderInfo.setValidationTime(new Date());
                        orderInfo.setValidationUserId(driverInfo.getUserId());
                        orderInfo.setValidationRealName(userService.getUser(driverInfo.getUserId()).getNickname());
                        orderInfo.setOrderStatus("2");
                        this.updateById(orderInfo);
                        //追加订单明细记录
                        RescueOrderDetail detail =new RescueOrderDetail();
                        detail.setRescueOrderId(orderInfo.getId());
                        detail.setRecordMoney(orderInfo.getSetMoney());
                        detail.setRecordTime(new Date());
                        detail.setRecordType("1");
                        detail.setRescueDetailInfo("支付成功");
                        orderDetailService.save(detail);
                        //追加救援工单记录
                        Double s = Double.valueOf(orderInfo.getSetMoney())/100d;
                        detailService.save(new RescueInfoDetail(rescueInfo.getId(),"0","用户支付完成","用户支付费用："+s));
                    }
                } catch (Exception e){
                   log.error(e.getMessage());
                }  finally{
                    //要主动释放锁
                    lock.unlock();
                }
            }
        }catch (Exception e){
            log.error(e.getMessage());
        }

        Map<String, String> res = new HashMap<>();
        res.put("code", "SUCCESS");
        res.put("message", "成功");
        return res;
    }


    @Override
    public void reviewOrder(String rescueInfoId, Integer starLevel, String reviewStr) throws Exception {
        RescueInfo rescueInfo = rescueInfoService.getById(rescueInfoId);
        LambdaQueryWrapper<RescueOrderInfo> queryWrapper =new LambdaQueryWrapper<>();
        queryWrapper.eq(RescueOrderInfo::getRescueInfoId,rescueInfoId).last("limit 1");
        RescueOrderInfo orderInfo = this.getOne(queryWrapper);
        Long orderId = orderInfo.getId();
        LambdaUpdateWrapper<RescueOrderInfo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(RescueOrderInfo::getId, orderId)
                .set(RescueOrderInfo::getCommentTime,new Date())
                .set(RescueOrderInfo::getCommentStar, starLevel).set(RescueOrderInfo::getCommentDesc, reviewStr)
                .set(RescueOrderInfo::getOrderStatus, "3");
        this.update(wrapper);
        //追加订单明细记录
        RescueOrderDetail detail =new RescueOrderDetail();
        detail.setRescueOrderId(orderInfo.getId());
        detail.setRecordMoney(0l);
        detail.setRecordTime(new Date());
        detail.setRecordType("1");
        detail.setRescueDetailInfo("评论订单");
        orderDetailService.save(detail);
        //计算当前司机评分
        if (ObjectUtil.isNotEmpty(rescueInfo.getDriverId())) {
            Double score = baseMapper.avgPartnerScore(rescueInfo.getDriverId());
            DriverInfo driverInfo = driverInfoService.getById(rescueInfo.getDriverId());
            driverInfo.setAvgScore(score);
            driverInfoService.updateById(driverInfo);
        }
    }

    /**
     * @param type     count 数量  money 金额
     * @param timeType day 日 month 月 year 年
     * @return
     */
    @Override
    public List<Map<String, Object>> getRescueOrderCount(String type, String timeType) {
        List<Map<String, Object>> res = new ArrayList<>();
        Map<String, Object> resp = DateUtils.getDateTimeList(timeType);
        List<DateTime> dateList = (List<DateTime>) resp.get("dateList");
        DateTime startTime = (DateTime) resp.get("startTime");
        DateTime endTime = (DateTime) resp.get("endTime");
        LambdaQueryWrapper<RescueOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.between(RescueOrderInfo::getCreateTime, startTime, endTime);
        queryWrapper.eq(RescueOrderInfo::getOrderStatus, "3");
        List<RescueOrderInfo> list = this.list(queryWrapper);
        for (DateTime dateTime : dateList) {
            String name = DateUtils.getDateName(timeType, dateTime);
            Map<String, Object> map = new HashMap<>();
            DateTime endTime1 = DateUtils.getEndTime(timeType, dateTime);
            List<RescueOrderInfo> rescueOrderInfos = filterOrdersByDate(list, dateTime, endTime1);
            map.put("name", name);
            if ("count".equals(type)) {
                long count = rescueOrderInfos.stream().count();
                map.put("value", count);
            }else if ("money".equals(type)) {
                // 使用 stream() 计算总金额，并防止空指针异常
                long money = rescueOrderInfos.stream()
                        .filter(Objects::nonNull) // 过滤掉 null 对象
                        .filter(order -> Objects.nonNull(order.getPayMoney())) // 过滤掉 payMoney 为 null 的对象
                        .mapToLong(RescueOrderInfo::getPayMoney) // 获取支付金额
                        .sum(); // 计算总和
                //将分转为元
                map.put("value", (double)money / 100);
            }
            res.add(map);
        }
        return res;
    }

    /**
     * 根据日期范围过滤订单
     * @param orders
     * @param startDate
     * @param endDate
     * @return
     */
    public List<RescueOrderInfo> filterOrdersByDate(List<RescueOrderInfo> orders, Date startDate, Date endDate) {
        return orders.stream()
                .filter(order -> order.getOrderTime() != null &&
                        !order.getOrderTime().before(startDate) &&
                        !order.getOrderTime().after(endDate))
                .collect(Collectors.toList());
    }
}
