package com.fs.store.service.impl;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fs.common.annotation.DataScope;
import com.fs.common.core.domain.R;
import com.fs.common.exception.CustomException;
import com.fs.common.utils.DateUtils;
import com.fs.company.domain.CompanyUser;
import com.fs.company.service.ICompanyService;
import com.fs.company.service.ICompanyUserService;
import com.fs.huifuPay.dto.*;
import com.fs.pay.pay.util.PayUtil;
import com.fs.store.domain.*;
import com.fs.store.service.IFsStoreOrderService;
import com.fs.store.service.channel.PaymentHandler;
import com.fs.store.service.channel.PaymentHandlerHolder;
import com.fs.store.service.channel.param.PayProcessContext;
import com.fs.tzBank.TzBankService;
import com.fs.store.param.FsStoreStatisticsParam;
import com.fs.store.service.IFsCouponScheduleService;
import com.fs.store.vo.FsStorePaymentStatisticsVO;
import com.fs.system.service.ISysConfigService;
import com.fs.tzBank.utils.TzConfigUtils;
import com.fs.store.param.FsStorePaymentPayParam;
import com.fs.store.param.FsStorePaymentParam;
import com.fs.store.service.IFsUserService;
import com.fs.store.vo.FsStorePaymentVO;
import com.fs.wx.dto.OrderQueryRequest;
import com.fs.wx.dto.OrderQueryResponse;
import com.fs.wx.service.OrderQueryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.fs.store.mapper.FsStorePaymentMapper;
import com.fs.store.service.IFsStorePaymentService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 支付明细Service业务层处理
 *
 * @author fs
 * @date 2022-06-20
 */
@Service
public class FsStorePaymentServiceImpl implements IFsStorePaymentService
{
    protected final Logger logger = LoggerFactory.getLogger(FsStorePaymentServiceImpl.class);
    @Autowired
    private FsStorePaymentMapper fsStorePaymentMapper;
    @Autowired
    private IFsUserService userService;

    @Autowired
    private ICompanyUserService companyUserService;
    @Autowired
    private ICompanyService companyService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private IFsCouponScheduleService fsCouponScheduleService;
    @Autowired
    private TzBankService tzBankService;

    @Autowired
    private IFsStoreOrderService orderService;

    @Autowired
    private OrderQueryService orderQueryService;

    @Value("${wx.miniapp.configs[0].account}")
    private String account;

    /**
     * 查询支付明细
     *
     * @param paymentId 支付明细ID
     * @return 支付明细
     */
    @Override
    public FsStorePayment selectFsStorePaymentById(Long paymentId)
    {
        return fsStorePaymentMapper.selectFsStorePaymentById(paymentId);
    }

    /**
     * 查询支付明细列表
     *
     * @param fsStorePayment 支付明细
     * @return 支付明细
     */
    @Override
    public List<FsStorePayment> selectFsStorePaymentList(FsStorePayment fsStorePayment)
    {
        return fsStorePaymentMapper.selectFsStorePaymentList(fsStorePayment);
    }

    /**
     * 新增支付明细
     *
     * @param fsStorePayment 支付明细
     * @return 结果
     */
    @Override
    public int insertFsStorePayment(FsStorePayment fsStorePayment)
    {
        fsStorePayment.setCreateTime(DateUtils.getNowDate());
        return fsStorePaymentMapper.insertFsStorePayment(fsStorePayment);
    }

    /**
     * 修改支付明细
     *
     * @param fsStorePayment 支付明细
     * @return 结果
     */
    @Override
    public int updateFsStorePayment(FsStorePayment fsStorePayment)
    {
        return fsStorePaymentMapper.updateFsStorePayment(fsStorePayment);
    }

    /**
     * 批量删除支付明细
     *
     * @param paymentIds 需要删除的支付明细ID
     * @return 结果
     */
    @Override
    public int deleteFsStorePaymentByIds(Long[] paymentIds)
    {
        return fsStorePaymentMapper.deleteFsStorePaymentByIds(paymentIds);
    }

    /**
     * 删除支付明细信息
     *
     * @param paymentId 支付明细ID
     * @return 结果
     */
    @Override
    public int deleteFsStorePaymentById(Long paymentId)
    {
        return fsStorePaymentMapper.deleteFsStorePaymentById(paymentId);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
    public R payment(FsStorePaymentPayParam payment) {
        if(payment.getPayMoney().compareTo(new BigDecimal(0.0))<1){
            return R.error("支付金额必须大于0");
        }

        String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();

        CompanyUser companyUser=companyUserService.selectCompanyUserById(payment.getCompanyUserId());
        FsUser user=userService.selectFsUserById(payment.getUserId());


        String json = configService.selectConfigByKey("store.pay");
        FsPayConfig fsPayConfig = JSON.parseObject(json, FsPayConfig.class);
        FsStorePayment storePayment=new FsStorePayment();
        storePayment.setCompanyId(payment.getCompanyId());
        storePayment.setCompanyUserId(payment.getCompanyUserId());
        storePayment.setStatus(0);
        storePayment.setPayMode(fsPayConfig.getType());
        storePayment.setPayCode(orderSn);
        storePayment.setPayMoney(payment.getPayMoney());
        storePayment.setCreateTime(new Date());
        storePayment.setPayTypeCode("weixin");
        storePayment.setBusinessType(1);
        storePayment.setRemark(payment.getRemark());
        storePayment.setOpenId(user.getMaOpenId());
        storePayment.setUserId(user.getUserId());
        if(companyUser==null){
            return R.error("销售帐号不存在");
        }
        storePayment.setDeptId(companyUser.getDeptId());
        //易宝支付
        fsStorePaymentMapper.insertFsStorePayment(storePayment);
        PayProcessContext processContext = new PayProcessContext();
        processContext.setOrderId(null);
        processContext.setPayType(null);
        processContext.setPaymentId(storePayment.getPaymentId());
        processContext.setPayCode(orderSn);
        processContext.setFsPayConfig(fsPayConfig);
        processContext.setUserId(user.getUserId());
        processContext.setGoodsInfo("医学管理方案服务");
        processContext.setOrderPrefix("payment-");
        PaymentHandler paymentHandler = PaymentHandlerHolder.findBest(fsPayConfig.getType());
        if(ObjectUtil.isNull(payment)){
            throw new CustomException("支付方式不存在");
        }
        return paymentHandler.createOrder(processContext);
    }

    @Override
    public FsStorePayment selectFsStorePaymentByCode(String payCode) {
        return fsStorePaymentMapper.selectFsStorePaymentByCode(payCode);
    }

    @Override
    public List<FsStorePaymentVO> selectFsStorePaymentListQuery(FsStorePaymentParam fsStorePayment) {
        return fsStorePaymentMapper.selectFsStorePaymentListQuery(fsStorePayment);
    }

    @Override
    public List<FsStorePaymentVO> exportFsStorePaymentList(FsStorePaymentParam fsStorePayment) {
        return fsStorePaymentMapper.exportFsStorePaymentList(fsStorePayment);
    }

    @Override
    @DataScope(deptAlias = "cu",userAlias = "cu")
    public List<FsStorePaymentVO> selectFsStorePaymentListQueryVO(FsStorePaymentParam fsStorePayment) {
        return fsStorePaymentMapper.selectFsStorePaymentListQueryVO(fsStorePayment);
    }

    @Override
    public List<FsStorePaymentVO> selectFsMyStorePaymentListQueryVO(FsStorePaymentParam fsStorePayment) {
        return fsStorePaymentMapper.selectFsMyStorePaymentListQueryVO(fsStorePayment);
    }

    @Override
    public List<FsStorePayment> selectFsStorePaymentByOrderId(Long orderId) {
        return fsStorePaymentMapper.selectFsStorePaymentByOrderId(orderId);
    }

    @Override
    public List<FsStorePayment> selectFsStorePaymentByOrderIdNew(Long orderId) {
        return fsStorePaymentMapper.selectFsStorePaymentByOrderIdNew(orderId);
    }

    @Override
    public Integer selectFsStorePaymentByOrderIdExists(Long orderId) {
        return fsStorePaymentMapper.selectFsStorePaymentByOrderIdExists(orderId);
    }

    @Override
    public Long selectFsStorePaymentCount(int type,Long companyId) {
        return fsStorePaymentMapper.selectFsStorePaymentCount(type,companyId);
    }

    @Override
    @Transactional
    public String payConfirm(String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
        //更新订单状态
        FsStorePayment storePayment=fsStorePaymentMapper.selectFsStorePaymentByCode(payCode);
        if(!storePayment.getStatus().equals(0)){
            return "";
        }
        storePayment.setStatus(1);
        storePayment.setPayTime(new Date());
        storePayment.setTradeNo(tradeNo);
        storePayment.setBankSerialNo(bankSerialNo);
        storePayment.setBankTransactionId(bankTransactionId);
        fsStorePaymentMapper.updateFsStorePayment(storePayment);
        //增加佣金
        if(storePayment.getCompanyId()!=null&&storePayment.getCompanyId()>0){
            companyService.addCompanyPaymentMoney(storePayment);
        }
        return "SUCCESS";
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public String refund(String orderCode) {
        FsStorePayment payment=fsStorePaymentMapper.selectFsStorePaymentByCode(orderCode);
        payment.setStatus(-1);
        payment.setRefundTime(new Date());
        fsStorePaymentMapper.updateFsStorePayment(payment);
        //收款 减去所有
        if(payment.getCompanyId()!=null&&payment.getCompanyId()>0){
            companyService.subCompanyPaymentMoney(payment);
        }
        // 退款将定时发放优惠券的状态设置为已退款
        fsCouponScheduleService.setScheduleCouponRefund(orderCode);
        return "success";
    }

    @Override
    public List<JSONObject> selectFsStorePaymentCounts(Map<String, Object> toMap) {
        return fsStorePaymentMapper.selectFsStorePaymentCounts(toMap);
    }

    @Override
    public List<FsStorePaymentStatisticsVO> selectFsStorePaymentStatisticsList(FsStoreStatisticsParam param) {
        return fsStorePaymentMapper.selectFsStorePaymentStatisticsList(param);
    }

    @Override
    public List<FsStorePayment> selectFsStorePaymentByOrder(Long orderId) {
        return fsStorePaymentMapper.selectFsStorePaymentByOrder(orderId);
    }

    @Override
    public FsStorePayment selectFsStorePaymentByTradeNo(String tradeNo) {
        return fsStorePaymentMapper.selectFsStorePaymentByTradeNo(tradeNo);
    }

    @Override
    public void paymentSync() {
        List<FsStorePayment> fsStorePayments = fsStorePaymentMapper.queryPendingDelayState();
        for (FsStorePayment fsStorePayment : fsStorePayments) {
            queryYb(fsStorePayment);
        }
    }

    @Override
    @Async
    public void delayQueryTzbk(FsStorePayment fsStorePayment){
        try {
            TimeUnit.SECONDS.sleep(30);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        this.queryTzbk(fsStorePayment);
    }

    @Override
    public boolean queryTzbk(FsStorePayment fsStorePayment) {
        logger.info("查询台州银行: {}",fsStorePayment);
        RequestDTO<QueryOrderRestDTO> requestDTO = new RequestDTO<>();

        QueryOrderRestDTO queryOrderRestDTO = new QueryOrderRestDTO();

        queryOrderRestDTO.setOrderFlowNo(fsStorePayment.getTradeNo());
        TzConfigInfoDTO tzConfigInfoDTO = TzConfigUtils.getConfig();

        queryOrderRestDTO.setPlatMerCstNo(tzConfigInfoDTO.getPlatMerCstNo());

        requestDTO.setReqBody(queryOrderRestDTO);
        requestDTO.setReqHeader(TzReqHeaderDTO.getInstance(fsStorePayment.getPayCode()));

        TzReqResultDTO<QueryOrderInfoDTO> resultDTO = null;
        try {
            resultDTO = tzBankService.payQueryOrder(requestDTO);
            logger.info("查询结果: {}",resultDTO);
            String retCode = resultDTO.getRetCode();
            // 如果查询支付成功
            if(retCode.equals("00000000")){
                QueryOrderInfoDTO body = resultDTO.getBody();
                String status = body.getStatus();
                Long orderId = fsStorePayment.getOrderId();
                String payCode = fsStorePayment.getPayCode();
                if("90".equals(status)){
                    // 如果查询支付成功 更新订单状态
                    orderService.payConfirm(1,orderId, fsStorePayment.getPayCode(),
                            fsStorePayment.getTradeNo(),body.getChlTrxId(), fsStorePayment.getTradeNo());

                    // 70交易失败 80订单关闭
                } else if("70".equals(status) || "80".equals(status)) {
                    fsStorePayment.setStatus(-2);
                    this.updateFsStorePayment(fsStorePayment);
                    return false;
                    // 10 初始状态 60交易中
                } else if("10".equals(status) || "60".equals(status)){
                    return false;
                }

                return true;
            }
        } catch (Exception e) {
            logger.error("台州银行支付回调查询失败:",e);
        }
        return false;
    }

    @Override
    public boolean queryYb(FsStorePayment fsStorePayment) {
        // 查询易宝

        OrderQueryRequest orderQueryRequest = new OrderQueryRequest();
        orderQueryRequest.setAccount(account);
        orderQueryRequest.setUpOrderId(fsStorePayment.getTradeNo());
        orderQueryRequest.setIsNeedUpInfo("1");

        String sign = PayUtil.sign(orderQueryRequest.toSignMap());
        orderQueryRequest.setSign(sign);

        OrderQueryResponse orderQueryResponse = orderQueryService.queryOrder(orderQueryRequest);
        if(ObjectUtil.equal(orderQueryResponse.getStatus(),100)){
            Long orderId = fsStorePayment.getOrderId();

            // 支付成功
            if("0".equals(orderQueryResponse.getState())){
                // 如果查询支付成功 更新订单状态
                cn.hutool.json.JSONObject upInfo = orderQueryResponse.getUpInfo();
                String bankTrxId = upInfo.getStr("bankTrxId");
                String bankOrderId = upInfo.getStr("bankOrderId");
                orderService.payConfirm(1,orderId, fsStorePayment.getPayCode(),
                        fsStorePayment.getTradeNo(),bankTrxId, bankOrderId);
                return true;
                // 1失败 2已撤销
            } else if("1".equals(orderQueryResponse.getState()) || "2".equals(orderQueryResponse.getState())){
                fsStorePayment.setStatus(-2);
                this.updateFsStorePayment(fsStorePayment);
                return false;
            }
        }
        return false;
    }

    @Override
    public boolean updateYbBankSerial(FsStorePayment fsStorePayment) {
        // 查询易宝

        OrderQueryRequest orderQueryRequest = new OrderQueryRequest();
        orderQueryRequest.setAccount(account);
        orderQueryRequest.setUpOrderId(fsStorePayment.getTradeNo());
        orderQueryRequest.setIsNeedUpInfo("1");

        String sign = PayUtil.sign(orderQueryRequest.toSignMap());
        orderQueryRequest.setSign(sign);

        OrderQueryResponse orderQueryResponse = orderQueryService.queryOrder(orderQueryRequest);
        if(ObjectUtil.equal(orderQueryResponse.getStatus(),100)){

            // 支付成功
            if("0".equals(orderQueryResponse.getState())){
                // 如果查询支付成功 更新订单状态
                cn.hutool.json.JSONObject upInfo = orderQueryResponse.getUpInfo();
                String bankTrxId = upInfo.getStr("bankTrxId");
                String bankOrderId = upInfo.getStr("bankOrderId");
                fsStorePayment.setBankTransactionId(bankTrxId);
                fsStorePayment.setBankSerialNo(bankOrderId);
                this.updateFsStorePayment(fsStorePayment);
                return true;
                // 1失败 2已撤销
            } else if("1".equals(orderQueryResponse.getState()) || "2".equals(orderQueryResponse.getState())){
                fsStorePayment.setStatus(-2);
                this.updateFsStorePayment(fsStorePayment);
                return false;
            }
        }
        return false;
    }

    @Override
    public List<FsStorePayment> queryByBankTrxId(List<String> bankTrxIds) {
        return fsStorePaymentMapper.queryByBankTrxId(bankTrxIds);
    }
}
