package com.leromro.core.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.leromro.common.constant.CommonConstants;
import com.leromro.common.core.domain.AjaxResult;
import com.leromro.common.core.domain.ListPermission;
import com.leromro.common.exception.ServiceException;
import com.leromro.common.utils.SecurityUtils;
import com.leromro.core.domain.*;
import com.leromro.core.domain.vo.OrderRefundVO;
import com.leromro.core.domain.vo.WebOrderRefundVO;
import com.leromro.core.mapper.*;
import com.leromro.core.utils.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.stat.inference.OneWayAnova;
import org.hibernate.validator.internal.constraintvalidators.bv.time.futureorpresent.FutureOrPresentValidatorForReadableInstant;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.leromro.core.service.IOrderRefundService;
import org.springframework.transaction.annotation.Transactional;

import static com.leromro.core.utils.BigDecimalUtil.yuanToFee;

/**
 * 订单取消/退款Service业务层处理
 *
 * @author ruoyi
 * @date 2025-04-21
 */
@Slf4j
@Service
public class OrderRefundServiceImpl extends ServiceImpl<OrderRefundMapper, OrderRefund> implements IOrderRefundService {
    @Autowired
    private OrderRefundMapper lOrderRefundMapper;
    @Autowired
    private SecondOrdersMapper secondOrdersMapper;
    @Autowired
    private PlatformFinanceMapper platformFinanceMapper;
    @Autowired
    private ClientAccountMapper clientAccountMapper;
    @Autowired
    private VolunteerReservationTimeMapper reservationTimeMapper;
    @Autowired
    private VolunteerWorkDateMapper workDateMapper;
    @Autowired
    private MainOrdersMapper mainOrdersMapper;
    @Autowired
    private ClientAccountChangeMapper clientAccountChangeMapper;
    @Autowired
    @Qualifier("wxMiniPayRefundService")
    private WxPayService wxMiniPayRefundService;

    /**
     * 查询订单取消/退款
     *
     * @param orderRefundId 订单取消/退款主键
     * @return 订单取消/退款
     */
    @Override
    public OrderRefund selectLOrderRefundByOrderRefundId(Long orderRefundId) {
        return lOrderRefundMapper.selectLOrderRefundByOrderRefundId(orderRefundId);
    }

    /**
     * 查询订单取消/退款列表
     *
     * @param orderRefund 订单取消/退款
     * @return 订单取消/退款
     */
    @Override
    public List<OrderRefund> selectLOrderRefundList(OrderRefund orderRefund) {
        return lOrderRefundMapper.selectLOrderRefundList(orderRefund);
    }

    /**
     * 新增订单取消/退款
     *
     * @param orderRefund 订单取消/退款
     * @return 结果
     */
    @Override
    @Transactional
    public AjaxResult insertLOrderRefund(OrderRefund orderRefund) {
        //如果订单，一次都没完成，那就直接不用审批，直接退。
        Long mainOrderId = orderRefund.getMainOrderId();
        //先查订单
        QueryWrapper<MainOrders> mainOrdersQueryWrapper = new QueryWrapper<MainOrders>().eq("main_order_id", mainOrderId);
        MainOrders mainOrders = mainOrdersMapper.selectOne(mainOrdersQueryWrapper);
        BigDecimal totalPrice = mainOrders.getServiceTotalPrice();
        orderRefund.setUserId(SecurityUtils.getUserId());
        orderRefund.setVolunteerId(mainOrders.getVolunteerId());
        //如果这个订单状态为1 (已支付) 未开始  可以直接退款
        if (mainOrders.getOrderStatus().equals("1")) {
            //查询小订单表
            QueryWrapper<SecondOrder> secondOrderQueryWrapper = new QueryWrapper<SecondOrder>().eq("main_order_id", mainOrderId);
            List<SecondOrder> secondOrderList = secondOrdersMapper.selectList(secondOrderQueryWrapper);
            String paymentMethod = mainOrders.getPaymentMethod();
            //通过支付方式来判断是余额还是微信 1 是余额  2是微信
            if (paymentMethod.equals("1")) {
                //修改，用户账户表 把钱数加上
                UpdateWrapper<ClientAccount> clientAccountUpdateWrapper = new UpdateWrapper<ClientAccount>().eq("user_id", mainOrders.getUserId()).setSql("balance = balance + " + totalPrice);
                clientAccountMapper.update(null, clientAccountUpdateWrapper);
                //查询用户账余额账户
                BigDecimal Oldbalance = clientAccountMapper.selectBalanceByuserID(mainOrders.getUserId()).getBalance();
                BigDecimal newBalance = Oldbalance.add(totalPrice);
                //由于钱是退到钱包的，所以，向钱包变更记录中添加一条数据
                ClientAccountChange clientAccountChange = ClientAccountChange.builder().userId(mainOrders.getUserId()).changeType("1").sourceType("2").changeMoney(totalPrice).beforeBalance(totalPrice).afterBalance(newBalance).mainOrderId(mainOrderId).build();
                clientAccountChange.setCreateTime(DateTimeUtil.getNowTime1());
                clientAccountChangeMapper.insert(clientAccountChange);

                // 修改平台流水
                updatePlatformFinanceChange(secondOrderList,0,1,2);
            } else if (mainOrders.getPaymentMethod().equals("2")) {
                // 微信退款
                WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
                        //订单号
                        .outTradeNo(mainOrders.getOutTradeNo())
                        //退款订单号(自己生成)
                        .outRefundNo(mainOrders.getOutTradeNo())
                        //金额
                        .totalFee(yuanToFee(totalPrice))
                        //退款金额
                        .refundFee(yuanToFee(totalPrice))
                        //退款类型
                        .refundFeeType("CNY")
                        //退款原因
                        .refundDesc(orderRefund.getRefundReason())
                        .notifyUrl(wxMiniPayRefundService.getConfig().getNotifyUrl())
                        .build();
                WxPayRefundResult wxPayRefundResult;
                try {
                    wxPayRefundResult = wxMiniPayRefundService.refund(refundInfo);
                    log.info("微信退款接口返回信息= {}", wxPayRefundResult);
                    //判断退款信息是否正确
                    if (wxPayRefundResult.getResultCode().equals("FAIL")){
                        throw new ServiceException(wxPayRefundResult.getErrCodeDes());
                    }
                } catch (WxPayException e) {
                    return AjaxResult.error("微信退款接口错误信息:"+e.getMessage());
                }

            } else {
                throw new RuntimeException("该支付方式还未开通退款功能");
            }

            //修改主、小订单状态 全额退款，设置主订单的状态为6 已取消
            mainOrders.setOrderStatus("1".equals(paymentMethod)?"6":"8");
            updateMainOrderAndSeconderStatus(mainOrders,"1".equals(paymentMethod)?"6":"8");
            //修改志愿者的工作时间以及日期
            updateVolunteerWorkDateAndTime(secondOrderList, mainOrders);

            //在退款记录标中生成数据，状态为 已退款
            orderRefund.setStatus("1".equals(paymentMethod)?"2":"1");
            orderRefund.setRefundAmount(totalPrice);
            this.save(orderRefund);
            return AjaxResult.success("钱款将在三个工作日内返回到您的钱包中");
        } else if (mainOrders.getOrderStatus().equals("3")) {
            //订单已开始或者订单已完成
            orderRefund.setStatus("0");
            orderRefund.setRefundAmount(mainOrders.getServiceOnePrice().multiply(BigDecimal.valueOf(mainOrders.getSingleQuantity())).multiply(new BigDecimal(mainOrders.getTotalTimes() - mainOrders.getFinishTimes())));
            this.save(orderRefund);
            UpdateWrapper<MainOrders> mainOrderUpdateWrapper = new UpdateWrapper<MainOrders>().eq("main_order_id", mainOrderId).set("order_status", "5");
            mainOrdersMapper.update(null, mainOrderUpdateWrapper);
            return AjaxResult.success("已提交申请");
        } else if (mainOrders.getOrderStatus().equals("4") || mainOrders.getOrderStatus().equals("8")) {
            return AjaxResult.success("订单已全部完成，不可退款");
        } else if (mainOrders.getOrderStatus().equals("5")) {
            return AjaxResult.success("订单退款申请正在审核中");
        } else if (mainOrders.getOrderStatus().equals("6") || mainOrders.getOrderStatus().equals("7")) {
            return AjaxResult.success("订单已退款或部分退款，不可重复退款");
        } else if (mainOrders.getOrderStatus().equals("0") || mainOrders.getOrderStatus().equals("2")) {
            return AjaxResult.success("订单未支付或支付失败，不可取消");
        } else {
            return AjaxResult.success("请联系管理员或检查订单状态");
        }

    }

    /**
     * 修改订单取消/退款
     *
     * @param orderRefund 订单取消/退款
     * @return 结果
     */
    @Override
    public Boolean updateLOrderRefund(OrderRefund orderRefund) {
        return this.updateById(orderRefund);
    }

    /**
     * 批量删除订单取消/退款
     *
     * @param orderRefundIds 需要删除的订单取消/退款主键
     * @return 结果
     */
    @Override
    public int deleteLOrderRefundByOrderRefundIds(Long[] orderRefundIds) {
        return lOrderRefundMapper.deleteLOrderRefundByOrderRefundIds(orderRefundIds);
    }

    /**
     * 删除订单取消/退款信息
     *
     * @param orderRefundId 订单取消/退款主键
     * @return 结果
     */
    @Override
    public int deleteLOrderRefundByOrderRefundId(Long orderRefundId) {
        return lOrderRefundMapper.deleteLOrderRefundByOrderRefundId(orderRefundId);
    }

    /**
     * 用户点击退款回显
     *
     * @param mainOrderId
     * @return
     */
    @Override
    public OrderRefundVO selectOrderRefundByMainOrderId(Long mainOrderId) {
        //根据mainID 取出
        MainOrders mainOrder = mainOrdersMapper.selectOne(new LambdaQueryWrapper<MainOrders>().eq(MainOrders::getMainOrderId, mainOrderId));
        OrderRefundVO refundVO = lOrderRefundMapper.selectOrderRefundInfoByMainOrderId(mainOrderId);
        refundVO.setRefundAmount(refundVO.getServiceOnePrice().multiply(BigDecimal.valueOf(mainOrder.getSingleQuantity())).multiply(new BigDecimal(refundVO.getTotalTimes() - refundVO.getFinishTimes())));

        QueryWrapper<SecondOrder> secondOrderQueryWrapper = new QueryWrapper<SecondOrder>().eq("main_order_id", mainOrderId).eq("order_status", "1");
        List<SecondOrder> secondOrderList = secondOrdersMapper.selectList(secondOrderQueryWrapper);
        refundVO.setSecondOrder(secondOrderList);
        return refundVO;
    }

    /**
     * @param
     */
    @Override
    @Transactional
    public AjaxResult checkOrderRefund(OrderRefund orderRefund1) {
        //传状态status ,主订单id，同意退款金额
        //只能单独审核
        //先查订单
        OrderRefund orderRefund = lOrderRefundMapper.selectById(orderRefund1.getOrderRefundId());
        //orderRefund.setStatus(orderRefund1.getStatus());
        BeanUtils.copyProperties(orderRefund1, orderRefund);
        Long mainOrderId = orderRefund.getMainOrderId();
        QueryWrapper<MainOrders> mainOrdersQueryWrapper = new QueryWrapper<MainOrders>().eq("main_order_id", mainOrderId);
        MainOrders mainOrders = mainOrdersMapper.selectOne(mainOrdersQueryWrapper);
        //查询要修改的小订单的列表
        QueryWrapper<SecondOrder> secondOrderQueryWrapper = new QueryWrapper<SecondOrder>().eq("main_order_id", mainOrderId).eq("order_status", "1");
        List<SecondOrder> secondOrderList = secondOrdersMapper.selectList(secondOrderQueryWrapper);

        if (orderRefund.getStatus().equals("2")) {
            if (mainOrders.getPaymentMethod().equals("1")) {
                //查询用户账余额账户
                BigDecimal Oldbalance = clientAccountMapper.selectBalanceByuserID(mainOrders.getUserId()).getBalance();
                BigDecimal newBalance = Oldbalance.add(orderRefund.getRefundAmount());
                //向用户余额表中添加一条数据
                ClientAccountChange clientAccountChange = ClientAccountChange.builder().userId(mainOrders.getUserId()).changeType("1").sourceType("2").changeMoney(orderRefund.getRefundAmount()).beforeBalance(Oldbalance).afterBalance(newBalance).mainOrderId(mainOrderId).build();
                clientAccountChange.setCreateTime(DateTimeUtil.getNowTime1());
                clientAccountChangeMapper.insert(clientAccountChange);
                //恢复用户余额,用户账户表增加钱数
                UpdateWrapper<ClientAccount> clientAccountUpdateWrapper = new UpdateWrapper<ClientAccount>().eq("user_id", mainOrders.getUserId()).setSql("balance = balance + " + orderRefund.getRefundAmount());
                clientAccountMapper.update(null, clientAccountUpdateWrapper);

                //向平台流水表更改，减少其中的流水;
                updatePlatformFinanceChange(secondOrderList,0,1,2);
            } else if (mainOrders.getPaymentMethod().equals("2")) {
                //微信退款
                WxPayRefundRequest refundInfo = WxPayRefundRequest.newBuilder()
                        //订单号
                        .outTradeNo(mainOrders.getOutTradeNo())
                        //退款订单号(自己生成)
                        .outRefundNo(mainOrders.getOutTradeNo())
                        //金额
                        .totalFee(yuanToFee(mainOrders.getServiceTotalPrice()))
                        //退款金额
                        .refundFee(yuanToFee(orderRefund.getRefundAmount()))
                        //退款类型
                        .refundFeeType("CNY")
                        //退款原因
                        .refundDesc(orderRefund.getRefundReason())
                        .notifyUrl(wxMiniPayRefundService.getConfig().getNotifyUrl())
                        .build();
                WxPayRefundResult wxPayRefundResult;
                try {
                    wxPayRefundResult = wxMiniPayRefundService.refund(refundInfo);
                    log.info("微信退款接口返回信息= {}", wxPayRefundResult);
                    //判断退款信息是否正确
                    if (wxPayRefundResult.getResultCode().equals("FAIL")){
                        throw new ServiceException(wxPayRefundResult.getErrCodeDes());
                    }
                } catch (WxPayException e) {
                    return AjaxResult.error("微信退款接口错误信息:"+e.getMessage());
                }
            } else {
                throw new RuntimeException("该支付方式还未开通退款功能");
            }
            //更改状态 更改更新时间，更改审批状态、退款钱数、原因、图片。
            orderRefund.setUpdateTime(DateTimeUtil.getNowTime());
            lOrderRefundMapper.updateLOrderRefund(orderRefund);


            //修改志愿者的工作时间以及日期
            updateVolunteerWorkDateAndTime(secondOrderList,mainOrders);

            //部分退款，设置主订单的状态为 7
            mainOrders.setOrderStatus("7");
            //调用方法来修改主、小订单的状态
            updateMainOrderAndSeconderStatus(mainOrders,"6");


        } else if (orderRefund.getStatus().equals("3")) {
            //不通过
            orderRefund.setRefundApplyAmount(orderRefund.getRefundAmount());
            orderRefund.setRefundAmount(BigDecimal.valueOf(0));
            orderRefund.setUpdateTime(DateTimeUtil.getNowTime());
            //主订单修改状态 返回之前的状态
            if (mainOrders.getTotalTimes().equals(mainOrders.getFinishTimes())) {
                UpdateWrapper<MainOrders> mainOrdersMapperUpdateWrapper = new UpdateWrapper<MainOrders>().eq("main_order_id", mainOrderId).set("order_status", 4);
                mainOrdersMapper.update(null, mainOrdersMapperUpdateWrapper);
            } else {
                UpdateWrapper<MainOrders> mainOrdersMapperUpdateWrapper = new UpdateWrapper<MainOrders>().eq("main_order_id", mainOrderId).set("order_status", 3);
                mainOrdersMapper.update(null, mainOrdersMapperUpdateWrapper);
            }
            lOrderRefundMapper.updateLOrderRefund(orderRefund);
        }
        return AjaxResult.success();
    }

    /**
     * @param mainOrders
     * @return
     */
    @Override
    public List<WebOrderRefundVO> selectWebOrderRefundList(MainOrders mainOrders) {
        return lOrderRefundMapper.selectWebOrderRefundList(new ListPermission(OrderRefund.class, CommonConstants.CHECK_PROVINCE_CITY_DISTRICT) ,mainOrders);
    }

    //修改志愿者的工作时间
    public void updateVolunteerWorkDateAndTime(List<SecondOrder> secondOrderList, MainOrders mainOrders) {
        //修改志愿者工作时间表

        List<LocalDate> workDateList = secondOrderList.stream().map(SecondOrder::getWorkDate).collect(Collectors.toList());

        VolunteerReservationTime reservationTime =VolunteerReservationTime.builder().volunteerId(mainOrders.getVolunteerId()).clientId(mainOrders.getUserId()).build();
        List<VolunteerReservationTime> reservationTimes = new ArrayList<>();
        for (SecondOrder secondOrder : secondOrderList) {
            int parts = (int) (secondOrder.getServiceDuration() * mainOrders.getSingleQuantity() /30);
            if (secondOrder.getServiceDuration() % 30 != 0){
                parts++;
            }
            LocalTime workStartTime = secondOrder.getWorkStartTime();
            for (int i = 0; i < parts; i++) {
                VolunteerReservationTime reservationTime1 = new VolunteerReservationTime();
                BeanUtils.copyProperties(reservationTime,reservationTime1);
                reservationTime1.setReservationDate(secondOrder.getWorkDate());
                reservationTime1.setReservationTime(workStartTime);
                reservationTimes.add(reservationTime1);
                workStartTime = workStartTime.plusMinutes(30);
            }
        }
        //首先查出这个小订单的全部时间
        reservationTimeMapper.deleteVolunteerReservationTimeList(reservationTimes);
        //志愿者预约时间表 还有 修改志愿者工作日的预约状态。
        //先把志愿者预约状态全部设置为0//然后在查哪一天有预约，然后再把有的设置为1
        UpdateWrapper<VolunteerWorkDate> volunteerWorkDateUpdateWrapper1 = new UpdateWrapper<VolunteerWorkDate>().eq("volunteer_id", mainOrders.getVolunteerId()).set("has_reservation", 0);
        workDateMapper.update(null, volunteerWorkDateUpdateWrapper1);
        QueryWrapper<VolunteerReservationTime> reservationTimeQueryWrapper = new QueryWrapper<VolunteerReservationTime>().eq("volunteer_id", mainOrders.getVolunteerId());
        List<VolunteerReservationTime> reservationTimes1 = reservationTimeMapper.selectList(reservationTimeQueryWrapper);
        if (!reservationTimes1.isEmpty()) {
            List<LocalDate> reservationDate = reservationTimes1.stream().map(VolunteerReservationTime::getReservationDate).collect(Collectors.toList());
            UpdateWrapper<VolunteerWorkDate> volunteerWorkDateUpdateWrapper12 = new UpdateWrapper<VolunteerWorkDate>().eq("volunteer_id", mainOrders.getVolunteerId()).in("work_date", reservationDate).set("has_reservation", 1);
            workDateMapper.update(null, volunteerWorkDateUpdateWrapper12);
        }
    }

    //修改主、小订单的状态 小订单退款都是固定为6
    public void updateMainOrderAndSeconderStatus(MainOrders mainOrders,String secondOrderStatus){
        Long mainOrderId = mainOrders.getMainOrderId();
        String mainOrdersOrderStatus = mainOrders.getOrderStatus();
        //修改状态已取消，用主订单Id
        UpdateWrapper<MainOrders> mainOrderUpdateWrapper = new UpdateWrapper<MainOrders>().eq("main_order_id", mainOrderId).set("order_status",mainOrdersOrderStatus);
        mainOrdersMapper.update(null, mainOrderUpdateWrapper);
        //修改，小订单表
        UpdateWrapper<SecondOrder> secondOrderUpdateWrapper = new UpdateWrapper<SecondOrder>().eq("main_order_id", mainOrderId).in("order_status","0","1").set("order_status", secondOrderStatus);
        secondOrdersMapper.update(null, secondOrderUpdateWrapper);
    }

    //订单退款，向平台流水中添加数据
    public void  updatePlatformFinanceChange(List<SecondOrder> secondOrderList,Integer changeType,Integer moneyType, Integer sourceType){
        //平台资金流水表,扣减调总价。
        List<PlatformFinance> platformFinanceList = secondOrderList.stream().map(secondOrder -> {
            new PlatformFinance();
            return PlatformFinance.builder()
                    .changeMoney(secondOrder.getServiceTotalPrice()).changeType(changeType).moneyType(moneyType).sourceType(sourceType).secondOrderId(secondOrder.getSecondOrderId()).volunteerId(secondOrder.getVolunteerId())
                    .build();
        }).collect(Collectors.toList());
        platformFinanceMapper.insertPlatformFinanceList(platformFinanceList);
    }
}
