package cn.pluss.platform.device.impl;

import cn.pluss.platform.ali.AliService;
import cn.pluss.platform.api.Result;
import cn.pluss.platform.api.ResultCode;
import cn.pluss.platform.api.ResultGenerator;
import cn.pluss.platform.constants.Constant;
import cn.pluss.platform.device.MercDeviceRefundImageService;
import cn.pluss.platform.device.MercOrderDetailService;
import cn.pluss.platform.device.MercOrderExpressService;
import cn.pluss.platform.dto.MercOrderDetailDTO;
import cn.pluss.platform.entitiy.SettleTypeEnum;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.enums.DeviceOrderStatus;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.*;
import cn.pluss.platform.openAccount.OpenAccountRecordService;
import cn.pluss.platform.pay.PayService;
import cn.pluss.platform.phoneValidateCode.PhoneValidateCodeService;
import cn.pluss.platform.util.DateUtils;
import cn.pluss.platform.util.StringUtil;
import cn.pluss.platform.util.ValidateCodeUtil;
import cn.pluss.platform.vo.MercOrderExpressVO;
import cn.pluss.platform.yt.YtLogistHandler;
import cn.pluss.platform.yt.YtStatusEnum;
import cn.pluss.platform.yt.constant.YtConstant;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 订单详情表 服务实现类
 * </p>
 *
 * @author Djh
 * @since 2022-03-17
 */
@Service
public class MercOrderDetailServiceImpl extends ServiceImpl<MercOrderDetailMapper, MercOrderDetail> implements MercOrderDetailService {

    @Resource
    private MercOrderExpressMapper moeMapper;

    @Resource
    private MercOrderExpressDetailMapper moedMapper;

    @Resource
    private MercDeviceRefundImageService mdriService;

    @Resource
    private MercOrderNewMapper mercOrderNewMapper;

    @Resource
    private MerchantChannelStatusMapper merchantChannelStatusMapper;

    @Resource
    private PhoneValidateCodeService phoneValidateCodeService;

    @Setter(onMethod_ = {@Autowired, @Qualifier("ysPayOldService")})
    private PayService ysPayOldService;

    @Resource
    private AliService aliService;

    @Resource
    private ValidateCodeUtil validateCodeUtil;

    @Resource
    private YtLogistHandler ytLogistHandler;

    @Resource
    private MercOrderExpressService mercOrderExpressService;

    @Resource
    private OpenAccountRecordService openAccountRecordService;

    @Override
    public void receiving(Long id) {
        MercOrderDetail detail = baseMapper.selectById(id);
        MsgException.checkNull(detail,"订单数据异常");
        detail.setStatus(DeviceOrderStatus.COMPLETED.getStatus());
        baseMapper.updateById(detail);
    }

    /**
     * 查看物流信息
     * @param id
     * @return
     */
    @Override
    public MercOrderExpressVO getOrderExpressInfo(Long id) {
        MercOrderDetail detail = baseMapper.selectById(id);
        MsgException.checkNull(detail,"订单详情数据异常");
        MercOrderExpressVO vo = moeMapper.getByExpressNo(detail.getExpressNo());

        if(vo != null){
            vo.setServiceTelephone(YtConstant.YT_CUSTOMER_TELEPHONE);
            List<MercOrderExpressDetail> list = moedMapper.getByExpressNo(detail.getExpressNo());
            vo.setExpressDetailList(list);
            if(!list.isEmpty()){
                vo.setLogisticProvider(list.get(0).getLogisticProvider());
            }
        }
        return vo;
    }

    /**
     * 根据订单号查询订单详情
     * @param orderNo
     * @return
     */
    @Override
    public List<MercOrderDetail> getDetailByOrderNo(String orderNo,String status) {
        QueryWrapper<MercOrderDetail> queryWrapper = new QueryWrapper<MercOrderDetail>()
                .eq("orderNo",orderNo).orderByDesc("id");
        if(StringUtil.isNotEmpty(status) && !"-1".equals(status)){
            switch (status){
                case "1":
                    queryWrapper.eq("status",DeviceOrderStatus.COMPLETED.getStatus());
                    break;
                case "2":
                    queryWrapper.eq("status",DeviceOrderStatus.RECEIV_ING.getStatus());
                    break;
                case "3":
                    queryWrapper.in("status",DeviceOrderStatus.REFUND_ING.getStatus(),DeviceOrderStatus.REFUND_SUCC.getStatus(),DeviceOrderStatus.REFUND_FAIL.getStatus());
                    break;
            }
        }
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 设备订单退款
     * @param dto
     */
    @Override
    public void refund(MercOrderDetailDTO dto) {
        MsgException.checkNull(dto.getId(),"退款详情订单ID为空");
        MsgException.checkNull(dto.getRefundAmt(),"退款金额不能为空");
        MsgException.checkBlank(dto.getRefundReason(),"退款原因不能为空");
        if(dto.getPicList() == null || dto.getPicList().size() == 0){
            MsgException.throwException("请先上传图片");
        }
        MercOrderDetail detail = baseMapper.selectById(dto.getId());
        MsgException.checkNull(detail,"订单数据异常");
        //暂无物流信息 可以直接退款
        BigDecimal totalAmt = detail.getPrice().multiply(BigDecimal.valueOf(detail.getNum()));
        if(StringUtil.isEmpty(detail.getExpressNo())){
            totalAmt = totalAmt.add(detail.getPostage());
        }else{
            MercOrderExpressVO express = moeMapper.getByExpressNo(detail.getExpressNo());
            if(express == null){
                totalAmt = totalAmt.add(detail.getPostage());
            }else{
                if(YtStatusEnum.ACCEPT.getValue().equals(express.getStatus()) || YtStatusEnum.WAIT.getValue().equals(express.getStatus())){
                    totalAmt = totalAmt.add(detail.getPostage());
                }
            }
        }
        MsgException.check(dto.getRefundAmt().compareTo(totalAmt) > 0,"退款金额超出商品金额");
        if(DeviceOrderStatus.SUCC_PAY.getStatus().equals(detail.getStatus())
                || DeviceOrderStatus.RECEIV_ING.getStatus().equals(detail.getStatus())
                || DeviceOrderStatus.REFUND_FAIL.getStatus().equals(detail.getStatus())
                || DeviceOrderStatus.COMPLETED.getStatus().equals(detail.getStatus())){
            List<MercDeviceRefundImage> list = new ArrayList<>(16);
            for (String picUrl:dto.getPicList()) {
                MercDeviceRefundImage image = new MercDeviceRefundImage(detail,picUrl);
                list.add(image);
            }
            mdriService.saveBatch(list);
            detail.setRefundAmt(dto.getRefundAmt());
            detail.setRefundTime(DateUtils.currentDate());
            detail.setRefundReason(dto.getRefundReason());
            detail.setRefundType(detail.getType());
            detail.setStatus(DeviceOrderStatus.REFUND_ING.getStatus());
            baseMapper.updateById(detail);
            return;
        }
        MsgException.throwException("只有“已支付”或“待收货”的订单才能发起退款申请！");
    }

    /**
     * 设置退款单号
     * @param dto
     */
    @Override
    public void setRefundExpressNo(MercOrderDetailDTO dto) {
        MsgException.checkNull(dto.getId(),"退款详情订单ID为空");
        MsgException.checkBlank(dto.getRefundExpressNo(),"退款物流单号不能为空");
        dto.setStatus(MercOrderDetail.STATUS_REFUND_AGREE);
        baseMapper.updateById(dto);
    }

    /**
     * 审核退款
     * @param orderDetail
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> auditRefund(MercOrderDetail orderDetail) {
        MsgException.checkNull(orderDetail.getId(),"退款详情订单ID为空");
        MsgException.checkBlank(orderDetail.getStatus(),"状态不能为空");
        MsgException.checkNull(orderDetail.getRefundAmt(),"退款金额不能为空");
        if(MercOrderDetail.STATUS_REFUND_FAIL.equals(orderDetail.getStatus())){
            MsgException.checkBlank(orderDetail.getRejectRemark(),"退款驳回，驳回原因不能为空！");
        }
        MercOrderDetail detail = baseMapper.selectById(orderDetail.getId());
        MsgException.checkNull(detail,"退款详情ID有误！");
//        MsgException.check(!MercOrderDetail.STATUS_REFUND_AGREE.equals(detail.getStatus()),"只能处理退货退款中的订单！");
        BigDecimal useRefundAmt = baseMapper.getUseRefundAmtByOrderNo(detail.getOrderNo());
        BigDecimal totalOrderAmt = detail.getPrice().multiply(BigDecimal.valueOf(detail.getNum())).add(detail.getPostage());
        if(orderDetail.getRefundAmt().add(useRefundAmt).compareTo(totalOrderAmt) > 0){
            MsgException.throwException("退款金额超出当前订单可退款总额");
        }
        if(MercOrderDetail.STATUS_REFUND_SUCCESS.equals(orderDetail.getStatus())){
            phoneValidateCodeService.checkSmsVerifyCode(orderDetail.getPhone(),orderDetail.getVerifyCode());
            MercOrderNew orderByNo = mercOrderNewMapper.getOrderByNo(detail.getOrderNo());
            MsgException.checkNull(orderByNo,"订单有误！");
            Integer channel = orderByNo.getChannel();
            MsgException.checkNull(channel,"通道未知，退款失败");
            Map<String, Object> result = null;
            MerchantOrder order = new MerchantOrder();
            order.convert(orderByNo,orderDetail.getRefundAmt(), SettleTypeEnum.D1.getValue(), detail.getRefundReason());
            switch (channel){
                case 1:
                case 2:
                case 3:
                    MsgException.throwException("当前订单所属通道不支持退款");
                    break;
                case 4:
                    //银盛退款
                    MerchantChannelStatus channelInfo = merchantChannelStatusMapper.getByMerchantCode(orderByNo.getMerchantCode(), 4);
                    MsgException.checkNull(channelInfo,"收款商户通道信息异常！");
                    result = ysPayOldService.refundPay(order, channelInfo.getMerchantId());
                    break;
                case 5:
                    //原生通道退款 TODO 不支持微信支付 因为微信支付走对公账户 所以这里加一个验证
                    MsgException.check(!Constant.PAY_TYPE_ALIPAY.equals(orderByNo.getPayType()),"当前订单支付方式不支持退款！");
                    result = aliService.refundV2(detail);
                    break;
                default:
                    MsgException.throwException("未知通道");
                    break;
            }
            int code = (int)result.get("code");
            String msg = (String) result.get("msg");
            String refundNo = (String) result.get("refundNo");
            if(code != ResultCode.SUCCESS.code()){
                return ResultGenerator.genFailResult(msg);
            }
            detail.setRefundTime(DateUtils.currentDate());
            detail.setRefundRemark(msg);
            detail.setRefundNo(refundNo);

            //开户奖扣除
            openAccountRecordService.removeOpenAccount(detail.getOrderNo());
        }
        detail.setRefundAmt(orderDetail.getRefundAmt());
        detail.setStatus(orderDetail.getStatus());
        detail.setRejectRemark(orderDetail.getRejectRemark());
        baseMapper.updateById(detail);
        return ResultGenerator.genSuccessResult("处理成功",null);
    }

    @Override
    public Result<Object> getVerifyCode(PhoneValidateCode phoneValidateCode) {
        MsgException.checkBlank(phoneValidateCode.getPhone(),"获取失败，手机号为空");
        String checkCode = StringUtil.random(4);
        phoneValidateCode.setCode(checkCode);
        JSONObject result = validateCodeUtil.requestManageValidateCode(phoneValidateCode.getPhone(),checkCode);
        if(result.getIntValue("code") != ResultCode.SUCCESS.code()){
            return ResultGenerator.genFailResult(result.getString("msg"));
        }
        phoneValidateCode.setSendDt(DateUtils.currentDate());
        phoneValidateCode.setStatus("1");
        phoneValidateCodeService.savePhoneValidateCode(phoneValidateCode);
        return ResultGenerator.genSuccessResult("获取成功",null);
    }

    /**
     * 推送物流信息
     * @param ids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Object> printLogistInfo(List<Long> ids) {
        MsgException.check(ids.isEmpty(),"未选中订单数据!");
        List<MercOrderDetail> list = baseMapper.selectBatchIds(ids);
        MsgException.check(list.isEmpty(),"订单数据异常!");
        boolean flag = false;
        for (MercOrderDetail detail:list) {
            if(!MercOrderDetail.STATUS_PAYED.equals(detail.getStatus())){
                flag = true;
                break;
            }
        }
        MsgException.check(flag,"只能处理已支付的订单!");
        MercOrderDetail detail = list.get(0);
        MercOrderNew order = mercOrderNewMapper.getOrderByNo(detail.getOrderNo());
        MsgException.checkNull(order,"订单数据异常!");
        JSONObject result = ytLogistHandler.createYtOrderV2(list,order);
        if(result.getIntValue("code") != ResultCode.SUCCESS.code()){
            MsgException.throwException(result.getString("message"));
        }
        JSONObject data = result.getJSONObject("data");
        UpdateWrapper<MercOrderDetail> updateWrapper = new UpdateWrapper<MercOrderDetail>().in("id",ids)
                .set("logistNo",data.getString("logistNo")).set("expressNo",data.getString("expressNo"))
                .set("status",MercOrderDetail.STATUS_UN_RECEIVED);
        update(updateWrapper);
        MercOrderExpress  orderExpress = new MercOrderExpress();
        orderExpress.setOrderNo(order.getOrderNo());
        orderExpress.setLogistNo(data.getString("logistNo"));
        orderExpress.setExpressNo(data.getString("expressNo"));
        orderExpress.setType(MercOrderExpress.EXPRESS_TYPE_HAIR);
        orderExpress.setStatus(YtStatusEnum.ACCEPT.getValue());
        mercOrderExpressService.save(orderExpress);
        return ResultGenerator.genSuccessResult("处理成功",null);
    }

    /**
     * 分页查询
     * @param page
     * @param condition
     * @return
     */
    @Override
    public Page<MercOrderDetail> pageInfo(Page<MercOrderDetail> page, MercOrderDetail condition) {
        return baseMapper.pageInfo(page,condition);
    }

    @Override
    public void refundReject(MercOrderDetail orderDetail) {
        final MercOrderDetail exist = baseMapper.selectById(orderDetail.getId());
        exist.setStatus(MercOrderDetail.STATUS_REFUND_FAIL);
        exist.setRejectRemark(orderDetail.getRejectRemark());
        baseMapper.updateById(exist);
    }

    @Override
    public void refundAgree(Long id) {
        final MercOrderDetail exist = baseMapper.selectById(id);
        exist.setStatus(MercOrderDetail.STATUS_REFUNDING);
        baseMapper.updateById(exist);
    }

    /**
     * 填写快递单号
     * @param id
     * @param expressNo
     * @return
     */
    @Override
    public Result<Object> inputExpressNo(Long id, String expressNo) {
        MsgException.checkNull(id,"订单ID不能为空!");
        MsgException.checkBlank(expressNo,"快递单号不能为空!");
        MercOrderDetail detail = baseMapper.selectById(id);
        MsgException.checkNull(detail,"订单数据异常!");
        MsgException.check(!MercOrderDetail.STATUS_PAYED.equals(detail.getStatus()),"只能处理已支付的订单数据");
        MsgException.check(StringUtil.isNotEmpty(detail.getExpressNo()),"当前订单已存在物流单号,请勿重复填写");
        detail.setStatus(MercOrderDetail.STATUS_UN_RECEIVED);
        detail.setExpressNo(expressNo);
        MercOrderExpress express = mercOrderExpressService.getByExpressNo(expressNo);
        if(express == null){
            express = new MercOrderExpress();
            express.setLogistNo(detail.getLogistNo());
            express.setOrderNo(detail.getOrderNo());
            express.setExpressNo(expressNo);
            express.setType(MercOrderExpress.EXPRESS_TYPE_HAIR);
            express.setStatus(YtStatusEnum.ACCEPT.getValue());
            mercOrderExpressService.save(express);
        }
        baseMapper.updateById(detail);
        return ResultGenerator.genSuccessResult("操作成功",null);
    }

    /**
     * 根据订单号和code查询订单信息
     * @param orderNo
     * @param code
     * @return
     */
    @Override
    public List<MercOrderDetail> listByOrderNoAndCode(String orderNo, String code) {
        return baseMapper.listByOrderNoAndCode(orderNo,code);
    }
}
