package cn.qg.qaplatform.service.impl;

import cn.qg.qaplatform.config.WebSocketServer;
import cn.qg.qaplatform.domain.ApplyDataVo;
import cn.qg.qaplatform.domain.GenLoanUser;
import cn.qg.qaplatform.process.Xyqb;
import cn.qg.qaplatform.service.QueryInProcessStatusService;
import cn.qg.qaplatform.service.XyqbDataService;
import cn.qg.qaplatform.service.QueryBasicLoanStatusDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URISyntaxException;
import java.util.Map;


@Service
@Slf4j
public class XyqbDataServiceImpl implements XyqbDataService {

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    QueryBasicLoanStatusDataService queryBasicLoanStatusDataService;

    @Autowired
    QueryInProcessStatusService queryInProcessStatusService;

    /**
     * 分配资产计划
     * @param namespace
     * @param fundId
     * @return
     */
    @Override
    public boolean assignFundCorp(String namespace, Integer fundId, String symbol) {
        Xyqb.symbol = symbol;
        // 登录资金方OP
        String fundOpToken = Xyqb.loginFundOP(namespace);
        boolean isAleadyAssign = false;
        // 检查是否已分配资产计划
        try {
            isAleadyAssign = Xyqb.assignFundOrNot(namespace, fundId, fundOpToken);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        boolean assignResult = false;
        boolean unblockResult = false;
        // 如果未分配
        if (!isAleadyAssign) {
            // 分配资产计划
            assignResult = Xyqb.setFundPlan(namespace, fundId, fundOpToken);
            // 打开推送放款
            unblockResult = Xyqb.unblockLoan(namespace, fundId, fundOpToken);
            if (assignResult && unblockResult) {
                return true;
            }
            return false;
        } else {
            return true;
        }
    }

    /**
     * 授信
     * @param applyDataVo 造数据的相关信息
     * @return
     * @throws Exception
     */
    @Override
    public boolean quotaAuth(ApplyDataVo applyDataVo, boolean auditResult) throws Exception {
        String namespace = applyDataVo.getNamespace();
        String phoneNo = applyDataVo.getPhoneNo();
        Integer channelId = applyDataVo.getChannel();
        Integer fundId = applyDataVo.getFundId();
        Integer amount = applyDataVo.getAmount();
        Integer term = applyDataVo.getTerm();
        String symbol = applyDataVo.getSymbol();
        String name = applyDataVo.getName();
        String idCardNo = applyDataVo.getIdCardNo();

        // 登录
        String token = Xyqb.login(namespace, channelId, phoneNo);
        // 查询用户中心id
        Map map = Xyqb.checkUserId(namespace, phoneNo);
        String uuid = map.get("uuid").toString();
        String userId = map.get("id").toString();
        // 同步session到xyqb
        Xyqb.syncSessionToXyqb(namespace, token);
        // 授信session同步
        Xyqb.creditSessionSync(namespace, "1", token);
        // 实名认证
        Xyqb.realNameAuth(namespace, token, name, idCardNo);
        // 基本信息认证
        Xyqb.authBasicInfo(namespace, token);
        // 进入上传身份证页
        String ocrToken = Xyqb.enterAuthOcr(namespace, token);
        // 上传身份证正面
        Xyqb.uploadFrontOfIdCard(ocrToken);
        // 上传身份证反面
        Xyqb.uploadBackOfIdCard(ocrToken);
        // 提交拍照认证
        Xyqb.submitPhotoAuth(ocrToken);
        // 授信
        Xyqb.credit(namespace, phoneNo, userId, uuid);
        // 提交审核
        Xyqb.submitAudit(namespace, token);
        // 查询用户审核记录
        Map authResult = Xyqb.queryUserAuditRecord(namespace, userId);
        String orderNo = authResult.get("order_no").toString().trim();
        String productId = authResult.get("product_id").toString();
        // 风控授信回调
        boolean creditResult = Xyqb.creditAuthNotify(namespace, token, uuid, channelId, fundId, orderNo, 0, auditResult, amount, term);
        // 风控授信回调成功，redis值为0
        if (creditResult) {
            setUserStatusRedisValue(namespace, phoneNo, 0);
        } else {
            setUserStatusRedisValue(namespace, phoneNo, 1);
        }
        return creditResult;
    }

    /**
     * 提现
     * @param applyDataVo 造数据相关信息
     * @param auditResult 二次风控成功or失败
     * @return
     * @throws Exception
     */
    @Override
    public boolean withDraw(ApplyDataVo applyDataVo, boolean auditResult) throws Exception {
        String namespace = applyDataVo.getNamespace();
        String phoneNo = applyDataVo.getPhoneNo();
        Integer channelId = applyDataVo.getChannel();
        Integer fundId = applyDataVo.getFundId();
        Integer amount = applyDataVo.getAmount();
        Integer term = applyDataVo.getTerm();
        String bankCardNo = applyDataVo.getBankCardNo();
        String bankCode = applyDataVo.getBankCode();

        // 登录
        String token = Xyqb.login(namespace, channelId, phoneNo);
        // 查询用户中心id
        Map map = Xyqb.checkUserId(namespace, phoneNo);
        String uuid = map.get("uuid").toString();
        String userId = map.get("id").toString();
        // 同步session到xyqb
        Xyqb.syncSessionToXyqb(namespace, token);
        // 查询用户审核记录
        Map authResult = Xyqb.queryUserAuditRecord(namespace, userId);
        String orderNo = authResult.get("order_no").toString().trim();
        String productId = authResult.get("product_id").toString();
        Long accountId;
        // 查询accountId
        try {
            accountId = Xyqb.getUserAccountId(namespace, userId, productId);
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            log.info("资方分配失败，quota_account表中无法查询到accountId!");
            return false;
        }
        // 绑卡
        String payToken = Xyqb.bindCard(namespace, token, accountId);
        // 绑卡发送短信
        Xyqb.cardAuthSms(namespace, payToken, phoneNo, bankCardNo, bankCode);
        // 绑卡确认
        Xyqb.cardAuthSmsConfirm(namespace, payToken, bankCardNo);
        // 获取绑卡列表
        Map firstCard = Xyqb.getBindCardList(namespace, token, accountId);
        Integer cardId = (Integer) firstCard.get("id");
        Integer cardBindInfoId = (Integer) firstCard.get("cardBindInfoId");
        // 绑卡后提现
        Integer loanId = Xyqb.createLoan(namespace, token, amount, term, accountId, productId, cardId, cardBindInfoId);
        // 二次风控
        boolean result = Xyqb.externalQuotaOrderAuditNotify(namespace, channelId, token, uuid, loanId, 0, auditResult);
        // 修改合同状态
        Xyqb.modifyContactStatus(namespace, userId);
        if (result) {
            setUserStatusRedisValue(namespace, phoneNo, 2);
        }
        return result;
    }

    /**
     * 放款
     * @param applyDataVo
     * @return
     */
    @Override
    public boolean makeLoan(ApplyDataVo applyDataVo, boolean payStatus) throws Exception {
        String namespace = applyDataVo.getNamespace();
        String phoneNo = applyDataVo.getPhoneNo();
        Integer channelId = applyDataVo.getChannel();
        Integer fundId = applyDataVo.getFundId();
        Integer amount = applyDataVo.getAmount();
        Integer term = applyDataVo.getTerm();

        // 登录
        String token = Xyqb.login(namespace, channelId, phoneNo);
        // 查询用户中心id
        Map map = Xyqb.checkUserId(namespace, phoneNo);
        String uuid = map.get("uuid").toString();
        String userId = map.get("id").toString();

        // 登录OP，获取token
        String opToken = Xyqb.loginOP(namespace);
        // 查询待打款数量
        Map<String, Integer> peopleMap = Xyqb.checkWaitingFundingCorpOperatePeople(namespace, fundId);
        Integer money = peopleMap.get("money");
        Integer people = peopleMap.get("people");
        // 修改待放款用户创建时间
        Integer loanId = Xyqb.getLoanId(namespace, userId);
        Xyqb.modifyWaitingFundingCreatedAt(namespace, loanId);
        Thread.sleep(5000);
        // 直接打款
        Xyqb.fundsPlanLoanApply(namespace,opToken, fundId, money, people);
        Thread.sleep(30000);
        // 放款结果通知
        boolean makeLoanResult = Xyqb.payNotify(namespace, loanId, payStatus);
        if (makeLoanResult) {
            setUserStatusRedisValue(namespace, phoneNo, 3);
        } else {
            setUserStatusRedisValue(namespace, phoneNo, 4);
        }
        return makeLoanResult;
    }

    /**
     * 设置redis值，查询状态
     * @param namespace
     * @param phoneNo
     * @param status 0-授信成功，1-授信失败，2-提现成功，3-放款成功，4-放款失败
     */
    public void setUserStatusRedisValue(String namespace, String phoneNo, Integer status) {
        String redisKey = namespace + "_" + phoneNo;
        redisTemplate.opsForValue().set(redisKey, status);
    }


    @Override
    public boolean genLoanUser(ApplyDataVo applyDataVo) throws Exception {
        Integer status = applyDataVo.getStatus();
        String namespace = applyDataVo.getNamespace();
        Integer fundId = applyDataVo.getFundId();
        String symbol = applyDataVo.getSymbol();
        String phoneNo = applyDataVo.getPhoneNo();

        WebSocketServer.sendInfo("本次请求的参数为：" + applyDataVo.toString(), symbol);
        log.info("本次请求的参数为：" + applyDataVo.toString());

        boolean assignFundResult = assignFundCorp(namespace, fundId, symbol);
        log.info("分配资金方的结果为：" + assignFundResult);

        /**
         * 0 - 审核通过
         */
        if (status == 0) {
            return quotaAuth(applyDataVo, true);
        }

        /**
         * 1 - 审核拒绝
         */
        if (status == 1) {
            return quotaAuth(applyDataVo, false);
        }

        /**
         * 2 - 放款中
         */
        if (status == 2) {
            boolean result = quotaAuth(applyDataVo, true);
            if (!result) {
                return false;
            }
            // 查询资方审核进度，如未分配成功，则阻塞下一步
            queryInProcessStatusService.queryFundingAssignProgress(namespace, phoneNo, fundId, symbol);
            return withDraw(applyDataVo, true);
        }

        /**
         * 3 - 放款成功
         */
        if (status == 3) {
            boolean quotaAuthResult = quotaAuth(applyDataVo, true);
            if (!quotaAuthResult) {
                return false;
            }
            // 查询资方审核进度，如未分配成功，则阻塞下一步
            queryInProcessStatusService.queryFundingAssignProgress(namespace, phoneNo, fundId, symbol);
            boolean withDrawResult =  withDraw(applyDataVo, true);
            if (!withDrawResult) {
                WebSocketServer.sendInfo("提现失败!", symbol);
                return false;
            }
            // 如果资方选择云信，则不需要手动调放款
            if (fundId == 1040) {
                WebSocketServer.sendInfo("提现成功，等待云信放款...", symbol);
                queryInProcessStatusService.queryLoanProgress(namespace, phoneNo, symbol);
                setUserStatusRedisValue(namespace, phoneNo, 3); // 因为没有调放款广达放款接口，因此需要手动设置redis值
                return true;
            }
            // 资方为平顶山，不需要手动放款
            if (fundId == 1030) {
                WebSocketServer.sendInfo("已完成二次风控，等待平银放款...", symbol);
                queryInProcessStatusService.queryLoanProgress(namespace, phoneNo, symbol);
                setUserStatusRedisValue(namespace, phoneNo, 3);
            }
            WebSocketServer.sendInfo("提现成功，10秒后放款!", symbol);
            Thread.sleep(10000);
            // 广达小贷-手动放款
            boolean makeLoanResult = makeLoan(applyDataVo, true);
            if (makeLoanResult) {
                WebSocketServer.sendInfo("放款成功!", symbol);
            } else {
                WebSocketServer.sendInfo("放款失败!", symbol);
            }
            return makeLoanResult;
        }

        /**
         * 4 - 放款失败
         */
        if (status == 4) {
            boolean quotaAuthResult = quotaAuth(applyDataVo, true);
            if (!quotaAuthResult) {
                return false;
            }
            // 查询资方审核进度，如未分配成功，则阻塞下一步
            queryInProcessStatusService.queryFundingAssignProgress(namespace, phoneNo, fundId, symbol);
            // 云南信托：二次风控失败，即代表放款失败
            if (fundId == 1040 || fundId == 1030) {
                withDraw(applyDataVo, false);
                WebSocketServer.sendInfo("放款失败！", symbol);
                setUserStatusRedisValue(namespace, phoneNo, 4);
                return true;
            }
            boolean withDrawResult =  withDraw(applyDataVo, true);
            if (!withDrawResult) {
                WebSocketServer.sendInfo("提现失败!", symbol);
                return false;
            }
            WebSocketServer.sendInfo("提现成功，10秒后放款!", symbol);
            Thread.sleep(10000);
            boolean makeLoanResult = makeLoan(applyDataVo, false);
            if (makeLoanResult) {
                WebSocketServer.sendInfo("放款失败!", symbol);
            }
            return makeLoanResult;

        }
        return false;
    }

    @Override
    public GenLoanUser queryUserStatus(String namespace, String phoneNo) {
        String redisResult = redisTemplate.opsForValue().get(namespace + "_" + phoneNo).toString();
        log.info("获取redis key结果为：" + redisResult);
        GenLoanUser genLoanUser = new GenLoanUser();
        genLoanUser = queryBasicLoanStatusDataService.getUserInfoByPhoneNo(namespace, phoneNo);
        genLoanUser.setFundId(queryBasicLoanStatusDataService.getAssignFundIdByUserId(namespace, genLoanUser.getUserId()));
        // 授信审核中
        if (redisResult.equals("0")) {
            genLoanUser.setStatus(0);
            genLoanUser.setDesc("授信审核中");
        }
        // 授信审核失败
        if (redisResult.equals("1")) {
            genLoanUser.setStatus(1);
            genLoanUser.setDesc("授信审核失败");
        }
        // 提现成功
        if (redisResult.equals("2")) {
            // 设置资方id
            genLoanUser.setStatus(2);
            genLoanUser.setDesc("提现成功");
        }
        // 提现失败
        if (redisResult.equals("10")) {
            genLoanUser.equals("10");
            genLoanUser.setDesc("资方分配失败");
        }
        // 放款成功
        if (redisResult.equals("3")) {
            genLoanUser.setStatus(3);
            genLoanUser.setDesc("放款成功");
        }
        // 放款失败
        if (redisResult.equals("4")) {
            genLoanUser.setStatus(4);
            genLoanUser.setDesc("放款失败");
        }
        return genLoanUser;
    }


}
