package com.ruoyi.frequency.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.code.DictConstant;
import com.ruoyi.code.PublicCommon;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.controller.req.OrdinaryAuthReq;
import com.ruoyi.enums.PlatformRecordEnums;
import com.ruoyi.enums.WalletDetailEnums;
import com.ruoyi.enums.message.AppMessageEnums;
import com.ruoyi.enums.process.ProcessResultEnums;
import com.ruoyi.enums.user.UserEnums;
import com.ruoyi.frequency.appmessage.service.AppMessageService;
import com.ruoyi.frequency.auth.entity.Auth;
import com.ruoyi.frequency.auth.mapper.AuthMapper;
import com.ruoyi.frequency.auth.model.result.AuthCount;
import com.ruoyi.frequency.auth.service.AuthService;
import com.ruoyi.frequency.customer.service.UserService;
import com.ruoyi.frequency.highendauth.entity.HighendAuth;
import com.ruoyi.frequency.highendauth.service.HighendAuthService;
import com.ruoyi.frequency.onlinerecord.service.OnlineRecordService;
import com.ruoyi.frequency.platformrecord.service.PlatformRecordService;
import com.ruoyi.frequency.store.entity.Store;
import com.ruoyi.frequency.store.service.StoreService;
import com.ruoyi.pay.enums.PayEnums;
import com.ruoyi.pay.enums.PaySourceEnums;
import com.ruoyi.pay.utils.AlipayCore;
import com.ruoyi.pay.utils.HttpRequestUtil;
import com.ruoyi.pay.utils.PayUtil;
import com.ruoyi.response.ResponseData;
import com.ruoyi.utils.BusinessUtil;
import com.ruoyi.vo.UserInfo;
import com.ruoyi.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台认证Service业务层处理
 *
 * @author liwenlong
 * @date 2023-10-18
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class AuthServiceImpl extends ServiceImpl<AuthMapper, Auth> implements AuthService {
    @Autowired
    private AuthMapper authMapper;

    @Autowired
    private UserService userService;

    /**
     * 查询平台认证
     *
     * @param id 平台认证主键
     * @return 平台认证
     */
    @Override
    public Auth selectAuthById(Long id) {
        Auth auth = authMapper.selectAuthById(id);

        if (auth != null) {
            Set<UserVo> userVoSet = new HashSet<>();

            userVoSet.add(new UserVo(UserEnums.store.getCode(), auth.getStoreId()));

            //查询用户信息
            Map<UserVo, UserInfo> userMap = userService.selectUserInfoMap(userVoSet, null);

            auth.setUserInfo(userMap.get(new UserVo(UserEnums.store.getCode(), auth.getStoreId())));
        }

        return auth;
    }

    /**
     * 查询平台认证列表
     *
     * @param auth 平台认证
     * @return 平台认证
     */
    @Override
    public List<Auth> selectAuthList(Auth auth) {

        List<Auth> auths = authList(auth);

        if (auths != null && auths.size() > 0) {
            Set<UserVo> userVoSet = auths.stream().map(s -> new UserVo(UserEnums.store.getCode(), s.getStoreId())).collect(Collectors.toSet());
            //查询用户信息
            Map<UserVo, UserInfo> userMap = userService.selectUserInfoMap(userVoSet, null);

            auths.stream().forEach(s -> {
                s.setUserInfo(userMap.get(new UserVo(UserEnums.store.getCode(), s.getStoreId())));
            });
        }

        return auths;
    }


    private List<Auth> authList(Auth auth) {
        List<Auth> auths = authMapper.selectAuthList(auth);
        return auths;
    }

    @Override
    public AuthCount statistics(Auth auth) {
        List<Auth> auths = authList(auth);
        List<Long> authIdList = auths.stream().map(x -> x.getId()).collect(Collectors.toList());
        authIdList.add(-1L);
        return authMapper.statistics(authIdList);
    }

    /**
     * 新增平台认证
     *
     * @param auth 平台认证
     * @return 结果
     */
    @Override
    public int insertAuth(Auth auth) {
        return authMapper.insertAuth(auth);
    }

    /**
     * 修改平台认证
     *
     * @param auth 平台认证
     * @return 结果
     */
    @Override
    public int updateAuth(Auth auth) {
        auth.setUpdateTime(DateUtils.getNowDate());
        return authMapper.updateAuth(auth);
    }

    /**
     * 批量删除平台认证
     *
     * @param ids 需要删除的平台认证主键
     * @return 结果
     */
    @Override
    public int deleteAuthByIds(Long[] ids) {
        this.lambdaUpdate().set(Auth::getDelFlag, PublicCommon.删除).in(Auth::getId, ids).update();
        return ids.length;
    }

    /**
     * 删除平台认证信息
     *
     * @param id 平台认证主键
     * @return 结果
     */
    @Override
    public int deleteAuthById(Long id) {
        this.lambdaUpdate().set(Auth::getDelFlag, PublicCommon.删除).eq(Auth::getId, id).update();
        return 1;
    }

    @Autowired
    private AppMessageService appMessageService;

    @Autowired
    private StoreService storeService;

    @Override
    public int process(Auth auth) {

        boolean update = this.lambdaUpdate().set(Auth::getResult, auth.getResult())
                .set(Auth::getReason, auth.getReason())
                .eq(Auth::getId, auth.getId())
                .update();

        if (update) {

            String wecomQrcode = auth.getWecomQrcode();

            auth = this.getById(auth.getId());
            //发送消息
            if (ProcessResultEnums.APPROVED.getCode().equals(auth.getResult())) {
                //成功
                appMessageService.addAppMessage(new UserVo(UserEnums.store.getCode(), auth.getStoreId()), auth.getId(), AppMessageEnums.AUTH_MESSAGE_SUSESS);

                storeService.lambdaUpdate().set(Store::getWecomQrcode, wecomQrcode)
                        .set(Store::getArea, auth.getArea())
                        .set(Store::getEnterDate, auth.getPracticeDate())
                        .eq(Store::getId, auth.getStoreId()).update();

            } else if (ProcessResultEnums.REJECTED.getCode().equals(auth.getResult())) {
                //失败
                appMessageService.addAppMessage(new UserVo(UserEnums.store.getCode(), auth.getStoreId()), auth.getId(), AppMessageEnums.AUTH_MESSAGE_FAIL);
            }
        }

        return 1;
    }

    @Autowired
    private PayUtil payUtil;

    @Autowired
    private BusinessUtil businessUtil;

    @Override
    public ResponseData ordinaryAuth(OrdinaryAuthReq req, UserVo userVo) {

        userService.storeByEnterprise(userVo);

        if (req.getType() == null) {
            req.setType(1);
        }
        //判断认证状态
        Auth auth = judgeAuthStatus(userVo, req.getType());

        //判断已支付/未支付 认证金额
        Boolean isPay = auth == null || auth.getIsOrdinaryPay() == 1;

        Auth newAuth = new Auth();
        BeanUtil.copyProperties(req, newAuth);
        newAuth.setStoreId(userVo.getUserId())
                .setIsOrdinaryPay(isPay ? 1 : 2)//普通认证是否缴纳 1没有 2 缴纳
                .setResult(PublicCommon.待审核);

        newAuth.setPracticeDate(DateUtil.parse(req.getPracticeDate(), "yyyy"));

        //支付与未支付走不同逻辑
        if (isPay) {
            //未支付
            return payAuth(newAuth, req, userVo);
        } else {
            //已支付
            return noPayAuth(newAuth, auth);
        }
    }


    /**
     * 支付--认证
     *
     * @return
     */
    private ResponseData payAuth(Auth newAuth, OrdinaryAuthReq req, UserVo userVo) {

        SysDictData dict = null;
        if (req.getType() == 1) {
            //查询字典配置--普通认证缴纳金额
            dict = businessUtil.getDict(DictConstant.普通认证缴纳金额);
        } else {
            //查询字典配置--酷家乐认证缴纳金额
            dict = businessUtil.getDict(DictConstant.酷家乐认证缴纳金额);
        }

        BigDecimal amount = dict == null ? BigDecimal.ZERO : new BigDecimal(dict.getDictValue());

        //支付金额
        newAuth.setAmount(amount);

        //余额支付 验证密码
        if (req.getPayType().equals(PayEnums.balance.getCode())) {
            //判断余额支付
            businessUtil.judgeBalancePay(userVo, amount, req.getPayPwd());
        }

        //支付订单号
        newAuth.setPayOrderNo(generateOrderNo());

        this.save(newAuth);

        //支付
        ResponseData responseData = payUtil.pay(userVo, newAuth.getId(), req.getPayType(), amount, BigDecimal.ZERO, newAuth.getPayOrderNo(), PaySourceEnums.auth_pay, WalletDetailEnums.PLATFORM_AUTH_PAY);

        if (responseData.getSuccess() || responseData.getCode().equals(210)) {
            //支付后操作
            if (req.getPayType().equals(PayEnums.balance.getCode()) || req.getPayType().equals(PayEnums.apple.getCode())) {
                after(newAuth);
            }
        }

        return responseData;
    }

    /**
     * 不用支付--认证
     *
     * @param newAuth
     * @param auth
     * @return
     */
    private ResponseData noPayAuth(Auth newAuth, Auth auth) {

        if (auth != null) {
            newAuth.setPayType(auth.getPayType())
                    .setPayStatus(auth.getPayStatus())
                    .setAmount(auth.getAmount());
        }
        this.save(newAuth);
        return ResponseData.success();
    }

    /**
     * 判断认证状态
     *
     * @param userVo
     */
    private Auth judgeAuthStatus(UserVo userVo, Integer type) {

        Auth auth = this.getOne(new QueryWrapper<Auth>().lambda()
                .eq(Auth::getStoreId, userVo.getUserId())
                .eq(Auth::getPayStatus, PublicCommon.Pay.已支付)
                .eq(Auth::getDelFlag, PublicCommon.启用)
        );

        //普通认证
        if (type == 1) {
            if (auth != null && ObjectUtil.isNotEmpty(auth.getResult())) {
                if (auth.getResult().equals(ProcessResultEnums.PENDING.getCode())) {
                    if (auth.getType() == 1) {
                        throw new CustomException("您已提交认证，请勿重复申请");
                    } else {
                        throw new CustomException("您正在进行酷家乐认证，请勿重复申请");
                    }
                } else if (auth.getResult().equals(ProcessResultEnums.APPROVED.getCode())) {
                    if (auth.getType() == 1) {
                        throw new CustomException("您已认证成功，请勿重复认证");
                    } else {
                        throw new CustomException("您已认证成功，请勿重复认证");
                    }
                }
            }
        }

        //酷家乐认证
        if (type == 3) {

            if (auth != null && ObjectUtil.isNotEmpty(auth.getResult())) {
                if (auth.getResult().equals(ProcessResultEnums.PENDING.getCode())) {
                    throw new CustomException("您正在进行普通认证，请勿重复申请");
                } else if (auth.getResult().equals(ProcessResultEnums.APPROVED.getCode())) {
                    throw new CustomException("您已进行酷家乐认证，请勿重复认证");
                }
            }

            //是否进行高端认证
            judgeAuthStatus(userVo);
        }

        if (auth != null) {
            //假删除认证记录
            this.lambdaUpdate().set(Auth::getDelFlag, PublicCommon.禁用).eq(Auth::getId, auth.getId()).update();
        }

        return auth;
    }

    @Autowired
    private HighendAuthService highendAuthService;

    /**
     * 判断认证状态
     *
     * @param userVo
     * @return
     */
    private HighendAuth judgeAuthStatus(UserVo userVo) {

        //判断认证状态
        HighendAuth auth = highendAuthService.getOne(new QueryWrapper<HighendAuth>().lambda()
                .eq(HighendAuth::getStoreId, userVo.getUserId())
                .eq(HighendAuth::getDelFlag, PublicCommon.启用)
        );
        if (auth != null) {
            if (auth.getStatus() < 3) {
                throw new CustomException("您正在进行高端认证，请勿重复认证");
            } else {
                throw new CustomException("您已进行高端认证，请勿重复认证");
            }
        }

        return auth;
    }

    @Autowired
    private PlatformRecordService platformRecordService;

    /**
     * 支付后操作
     *
     * @param auth
     */
    private void after(Auth auth) {
        this.lambdaUpdate().set(Auth::getPayStatus, PublicCommon.Pay.已支付)
                .set(Auth::getIsOrdinaryPay, 2)
                .eq(Auth::getId, auth.getId()).update();

        //平台流水
        platformRecordService.addPlatformRecord(new UserVo(UserEnums.store.getCode(), auth.getStoreId()), auth.getId(), auth.getAmount(), PlatformRecordEnums.PLATFORM_AUTH_PAY);
    }

    @Override
    public ResponseData<Auth> ordinaryAuthDetail(Integer type, UserVo userVo) {

        userService.storeByEnterprise(userVo);

        Auth auth = this.getOne(new QueryWrapper<Auth>().lambda()
                .eq(Auth::getStoreId, userVo.getUserId())
                .eq(Auth::getType, type)
                .eq(Auth::getDelFlag, PublicCommon.启用)
                .eq(Auth::getPayStatus, PublicCommon.Pay.已支付));
        return ResponseData.success(auth);
    }


    /**
     * 生成订单号
     *
     * @return
     */
    private String generateOrderNo() {
        String orderNo;
        String prefix = "PA";
        while (true) {
            orderNo = prefix + DateUtil.format(new Date(), "MMdd" + RandomUtil.randomNumbers(6));
            Auth old = this.getBaseMapper().selectOne(new QueryWrapper<Auth>().lambda()
                    .eq(Auth::getPayOrderNo, orderNo)

            );
            if (old == null) {
                break;
            }
        }
        return orderNo;
    }

    @Override
    public ResponseData authAliNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("******************************进入支付宝支付回调");
        //接收参数进行校验
        Map<String, String> paramsMap = AlipayCore.updateMap(request);
        //流水号
        String payId = paramsMap.get("out_trade_no");
        // 支付宝订单号
        String orderNo = paramsMap.get("trade_no");
        //付款状态
        String tradeStatus = paramsMap.get("trade_status");
        log.info("******************************payId=" + payId);

        Auth cur = baseMapper.selectOne(new QueryWrapper<Auth>().lambda().eq(Auth::getPayOrderNo, payId));
        if (cur == null) {
            log.error("支付信息丢失");
            return ResponseData.error("支付信息丢失");
        }
        if (cur.getPayStatus() == 2) {
            log.error("支付宝回调已经开始 回去吧");
            return ResponseData.error("支付宝回调已经开始 回去吧");
        }
        if (cur.getPayStatus() == 3) {
            //退款
            ResponseData responseData = payUtil.refund(new UserVo(UserEnums.store.getCode(), cur.getStoreId()), cur.getId(), cur.getPayType(), cur.getAmount(), cur.getAmount(), cur.getPayOrderNo(), cur.getAliBusinessId(), BigDecimal.ZERO);
            if (!responseData.getSuccess()) {
                log.error("退款失败：" + cur.getPayOrderNo());
            }
            return responseData;
        }
        if ("TRADE_SUCCESS".equalsIgnoreCase(tradeStatus)) {

            this.lambdaUpdate().set(Auth::getAliBusinessId, orderNo).eq(Auth::getId, cur.getId()).update();

            after(cur);//支付后逻辑处理
            log.info("正常");
            return ResponseData.success();
        } else {
            cur.setPayStatus(3);
            baseMapper.updateById(cur);
            log.error("支付失败");
        }
        return ResponseData.error("");
    }

    @Override
    public ResponseData authWxNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> requestMap = HttpRequestUtil.parseXml(request);
        System.out.println("requestMap:" + requestMap.toString());
        // 微信中的订单号
        String transactionId = requestMap.get("transaction_id");
        // 用户唯一标识
        String openid = requestMap.get("openid");
        //流水号
        String payId = requestMap.get("out_trade_no");

        Auth cur = baseMapper.selectOne(new QueryWrapper<Auth>().lambda().eq(Auth::getPayOrderNo, payId));
        if (cur == null) {
            log.error("支付信息丢失");
            return ResponseData.error("支付信息丢失");
        }
        if (cur.getPayStatus() == 2) {
            log.error("微信回调已经开始 回去吧");
            return ResponseData.error("支付宝回调已经开始 回去吧");
        }
        if (cur.getPayStatus() == 3) {
            //退款
            ResponseData responseData = payUtil.refund(new UserVo(UserEnums.store.getCode(), cur.getStoreId()), cur.getId(), cur.getPayType(), cur.getAmount(), cur.getAmount(), cur.getPayOrderNo(), cur.getAliBusinessId(), BigDecimal.ZERO);
            if (!responseData.getSuccess()) {
                log.error("退款失败：" + cur.getPayOrderNo());
            }
            return responseData;
        }

        if ("SUCCESS".equals(requestMap.get("result_code"))) {
            after(cur);//支付后逻辑处理
            log.info("正常");
            return ResponseData.success();
        } else {
            cur.setPayStatus(3);
            baseMapper.updateById(cur);
            log.error("支付失败");
        }

        return ResponseData.error("");
    }

    @Override
    public ResponseData authLakalaNotify(Map<String, String> requestMap) {
        System.out.println("requestMap:" + requestMap.toString());
        //流水号
        String payId = requestMap.get("out_order_no");
        Auth cur = baseMapper.selectOne(new QueryWrapper<Auth>().lambda().eq(Auth::getPayOrderNo, payId));
        if (cur == null) {
            log.error("支付信息丢失");
            return ResponseData.error("支付信息丢失");
        }
        if (cur.getPayStatus() == 2) {
            log.error("拉卡拉回调已经开始 回去吧");
            return ResponseData.error("拉卡拉回调已经开始 回去吧");
        }
        if (cur.getPayStatus() == 3) {
            //退款
            ResponseData responseData = payUtil.refund(new UserVo(UserEnums.store.getCode(), cur.getStoreId()), cur.getId(), cur.getPayType(), cur.getAmount(), cur.getAmount(), cur.getPayOrderNo(), cur.getAliBusinessId(), BigDecimal.ZERO);
            if (!responseData.getSuccess()) {
                log.error("退款失败：" + cur.getPayOrderNo());
            }
            return responseData;
        }

        //order_status 聚合收银台订单状态 	0:待支付 1:支付中 2:支付成功 3:支付失败 4:已过期 5:已取消 6：部分退款或者全部退款
        if (("2").equals(requestMap.get("order_status"))) {
            after(cur);//支付后逻辑处理
            log.info("正常");

            //设置成功标识
            businessUtil.setOutTradeNo(payId);

            //添加支付记录
            onlineRecordService.addOnlineRecord(new UserVo(UserEnums.customer.getCode(), cur.getStoreId()), cur.getId(), cur.getAmount(), WalletDetailEnums.PLATFORM_AUTH_PAY);

            return ResponseData.success();
        } else {
            cur.setPayStatus(3);
            baseMapper.updateById(cur);
            log.error("支付失败");
        }

        return ResponseData.error("");
    }

    @Autowired
    private OnlineRecordService onlineRecordService;
}
