package com.cool.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.LineInfoDAO;
import com.cool.store.entity.*;
import com.cool.store.enums.*;
import com.cool.store.exception.ApiException;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.*;
import com.cool.store.mq.util.HttpRestTemplateService;
import com.cool.store.request.*;
import com.cool.store.response.InitiatingResponse;
import com.cool.store.response.ResponseResult;
import com.cool.store.response.SigningBaseInfoResponse;
import com.cool.store.service.AliyunService;
import com.cool.store.service.IntentAgreementService;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.SecureUtil;
import com.cool.store.utils.StringUtil;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.utils.poi.constant.Constants;
import com.cool.store.vo.BusinessLicenseInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;


@Service
@Slf4j
public class IntentAgreementServiceImpl extends LineFlowService implements IntentAgreementService, AuditResultService {


    @Resource
    IntentAgreementMapper intentAgreementMapper;

    @Resource
    LineInfoMapper lineInfoMapper;

    @Resource
    JoinIntentionMapper joinIntentionMapper;

    @Resource
    LineInfoDAO lineInfoDAO;

    @Resource
    private HttpRestTemplateService httpRestTemplateService;

    @Value("${xfsg.url}")
    private String xfsgUrl;

    @Resource
    LineAuditInfoMapper lineAuditInfoMapper;

    @Resource
    LinePayMapper linePayMapper;

    @Resource
    HyOpenAreaInfoMapper openAreaInfoMapper;

    @Resource
    RedisUtilPool redisUtilPool;

    @Resource
    private CommonService commonService;

    @Resource
    AliyunService aliyunService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submit(IntentAgreementSubmitRequest request) {
        SigningBaseInfoDO signingBaseInfoDO = request.toSigningBaseInfoDO();
        boolean submitStatus = intentAgreementMapper.insert(signingBaseInfoDO);
        if (submitStatus) {
            LineInfoDO lineInfoDO = lineInfoMapper.getByPartnerId(request.getPartnerId());
            if (Objects.isNull(lineInfoDO)) {
                throw new ServiceException(ErrorCodeEnum.INTERVIEW_PARTNER_NOT_EXIST);
            }
            lineInfoDO.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode());
            lineInfoMapper.updateByPrimaryKeySelective(lineInfoDO);
            Map<String, String> requestMap = new HashMap<>();
            requestMap.put("partnerUsername", lineInfoDO.getUsername());
            requestMap.put("partnerMobile", lineInfoDO.getMobile());
            requestMap.put("lineId", String.valueOf(lineInfoDO.getId()));
            requestMap.put("submitTime", DateUtils.dateTimeNow(DateUtils.SPECIAL_DATE_START));
            commonService.sendMessage(Collections.singletonList(lineInfoDO.getInvestmentManager()),
                    MessageEnum.MESSAGE_30,
                    requestMap);
            return Boolean.TRUE;

        }
        return false;
    }

    @Override
    public SigningBaseInfoResponse getMiniIntentAgreement(String partnerId, Long lineId) {
        if (StringUtil.isBlank(partnerId) && lineId == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        SigningBaseInfoDO signingBaseInfoDO = intentAgreementMapper.selectByPartnerIdOrLineId(partnerId, lineId);
        if (Objects.isNull(signingBaseInfoDO)) {
            log.info("getMiniIntentAgreement signingBaseInfoDO IS NULL......");
            return null;
        }
        SigningBaseInfoResponse response = SigningBaseInfoResponse.from(signingBaseInfoDO);
        MemberQuestionDO byLineId = joinIntentionMapper.getByLineId(lineId);
        response.setType(byLineId.getJoinType());
        if (Objects.nonNull(signingBaseInfoDO.getAuditId())) {
            LineAuditInfoDO lineAuditInfoDO = lineAuditInfoMapper.selectByPrimaryKey(signingBaseInfoDO.getAuditId());
            if (Objects.isNull(lineAuditInfoDO)) {
                response.setRejectPublicReason(null);
            }
            response.setRejectPublicReason(lineAuditInfoDO.getRejectPublicReason());
        }
        return response;
    }

    @Override
    protected Boolean auditPass(Long auditId, LineInfoDO lineInfo, String userId) {
        //校验是否是审核节点
        if (!lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode()) &&
                !lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_75.getCode())) {
            throw new ServiceException(ErrorCodeEnum.NOT_APPROVE_NODE);
        }
        //待审核code 63 处理逻辑
        if (lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode())) {
            lineInfo.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_70.getCode());
            lineInfoDAO.updateLineInfo(lineInfo);
        }
        //待OA审核code 75 处理逻辑
        if (lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_75.getCode())) {
            WorkflowSubStageEnum workflowSubStageEnum = WorkflowSubStageEnum.getWorkflowSubStageEnum(lineInfo.getWorkflowSubStage());
            WorkflowSubStageEnum nextStage = workflowSubStageEnum.getNextStage();
            //更新线索阶段
            lineInfoDAO.updateWorkflowStage(lineInfo.getId(), nextStage, nextStage.getInitStatus(), userId);
            Map<String, String> requestMap = new HashMap<>();
            requestMap.put("partnerUsername", lineInfo.getUsername());
            requestMap.put("lineId", String.valueOf(lineInfo.getId()));
            requestMap.put("partnerMobile", lineInfo.getMobile());
            commonService.sendMessage(Collections.singletonList(lineInfo.getInvestmentManager()), MessageEnum.MESSAGE_32, requestMap);
            commonService.sendSms(lineInfo.getMobile(), SMSMsgEnum.INTENTION_PAYMENT_PASS);
        }
        //更新auditId
        SigningBaseInfoDO signingBaseInfoDO = intentAgreementMapper.selectByPartnerIdOrLineId(null, lineInfo.getId());
        if (Objects.nonNull(signingBaseInfoDO)) {
            intentAgreementMapper.updateAuditId(lineInfo.getId(), auditId);
        } else {
            throw new ServiceException("无法更新,没有对应的签约基本信息");
        }
        return Boolean.TRUE;
    }

    @Override
    protected Boolean auditReject(Long auditId, LineInfoDO lineInfo, String userId) {
        if ((!lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode()) &&
                !lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_75.getCode()))) {
            throw new ServiceException(ErrorCodeEnum.NOT_APPROVE_NODE);
        }
        //待审核code 63 处理逻辑
        if (lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode())) {
            lineInfo.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_65.getCode());
            lineInfo.setUpdateUserId(userId);
            lineInfoDAO.updateLineInfo(lineInfo);
            commonService.sendSms(lineInfo.getMobile(), SMSMsgEnum.INTENTION_PROTOCOL_FAIL);
        }
        //待OA审核code 75 处理逻辑
        if (lineInfo.getWorkflowSubStageStatus().equals(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_75.getCode())) {
            lineInfo.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_80.getCode());
            lineInfo.setUpdateUserId(userId);
            lineInfoDAO.updateLineInfo(lineInfo);
            //message
            Map<String, String> requestMap = new HashMap<>();
            requestMap.put("partnerUsername", lineInfo.getUsername());
            requestMap.put("lineId", String.valueOf(lineInfo.getId()));
            requestMap.put("submitTime", DateUtils.dateTimeNow(DateUtils.SPECIAL_DATE_START));
            commonService.sendMessage(Collections.singletonList(lineInfo.getInvestmentManager()),
                    MessageEnum.MESSAGE_31,
                    requestMap);
//            commonService.sendSms(lineInfo.getMobile(), SMSMsgEnum.INTENTION_PAYMENT_FAIL);
        }
        //更新auditId
        intentAgreementMapper.updateAuditId(lineInfo.getId(), auditId);
        return Boolean.TRUE;
    }


    @Override
    public ResponseResult initiating(InitiatingRequest request, LoginUserInfo user) {
        log.info("initiating request:{}", JSONObject.toJSONString(request));
        if (Objects.isNull(request)) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        verifyDate(request);
        String lockKey = "submitSignFranchise:" + request.getLineId();
        //流水
        String lockValue = UUID.randomUUID().toString();
        boolean acquired = false;
        try {
            acquired = redisUtilPool.setNxExpire(lockKey, lockValue, CommonConstants.TEN_SECONDS);
            if (Boolean.TRUE.equals(acquired)) {
                Map<String, Object> requestMap = new HashMap<>();
                fillSignatureInfo(requestMap);
                String url = xfsgUrl + Constants.INTENTION_CONTRACT_URL + "?timestamp=" + requestMap.get("timestamp") + "&signature=" + requestMap.get("signature");
                InitiatingDO initiatingDO = request.toInitiatingDO();
                initiatingDO.setApply_user(user.getJobNumber());
                initiatingDO.setApply_user_name(user.getName());
                LineInfoDO lineInfoDO = lineInfoMapper.getByLineId(request.getLineId());
                initiatingDO.setJmsxx(lineInfoDO.getPartnerNum());
                initiatingDO.setKdzBusinessId(AuditEnum.CONTRACT_INTENTION.getCode() + "_" + lineInfoDO.getId() + "_" + lineInfoDO.getWorkflowSubStageStatus());
                InitiatingResponse initiatingResponse = httpRestTemplateService.postForObject(url, initiatingDO, InitiatingResponse.class);
                if (initiatingResponse.getCode() != 0L) {
                    return new ResponseResult(500, initiatingResponse.getMsg(), initiatingResponse.getData());
                } else {
                    String redisKey = "OA:" + request.getMobile() + request.getIdCardNo();
                    log.info("initiating redisKey:{},request:{}", redisKey, JSONObject.toJSONString(request));
                    redisUtilPool.setString(redisKey, JSONObject.toJSONString(request));
                    lineInfoDO.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_75.getCode());
                    lineInfoMapper.updateByPrimaryKeySelective(lineInfoDO);
                    return new ResponseResult(200000, initiatingResponse.getMsg(), initiatingResponse.getData());
                }
            } else {
                throw new ServiceException(ErrorCodeEnum.DUPLICATE_SUBMISSION);
            }
        } finally {
            if (Boolean.TRUE.equals(acquired)) {
                String currentValue = redisUtilPool.getString(lockKey);
                if (lockValue.equals(currentValue)) {
                    redisUtilPool.delKey(lockKey);
                }
            }
        }

    }

    private void verifyDate(InitiatingRequest request) {
        if (request.getSignStartTime() == null || request.getSignEndTime() == null) {
            throw new ServiceException(ErrorCodeEnum.TIME_NULL_FALSE);
        }
        if (request.getSignStartTime().after(request.getSignEndTime())) {
            throw new ServiceException(ErrorCodeEnum.TIME_FALSE);
        }
    }

    @Override
    public InitiatingRequest getOaDetail(String mobile, String idCardNo) {
        String redisKey = "OA:" + mobile + idCardNo;
        String responseString = redisUtilPool.getString(redisKey);
        if (StringUtils.isNotBlank(responseString)) {
            return JSONObject.parseObject(responseString, InitiatingRequest.class);
        }
        return null;
    }

    @Override
    public ResponseResult save(FranchiseeSaveRequest request, LoginUserInfo user) throws ApiException {
        log.info("save request:{}", JSONObject.toJSONString(request));
        if (Objects.isNull(request)) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        String lockKey = "saveFranchise:" + request.getLineId();
        String lockValue = UUID.randomUUID().toString();
        boolean acquired = false;
        try {
            acquired = redisUtilPool.setNxExpire(lockKey, lockValue, CommonConstants.TEN_SECONDS);
            if (Boolean.TRUE.equals(acquired)) {
                Map<String, Object> requestMap = new HashMap<>();
                fillSignatureInfo(requestMap);
                String url = xfsgUrl + Constants.FRANCHISEE_STORE_NUM + "?timestamp=" + requestMap.get("timestamp") + "&signature=" + requestMap.get("signature");
                FranchiseeDO franchiseeDO = request.toFranchiseeDO();
                //查银行信息
                LinePayDO linePayDO = linePayMapper.getLinePayByLineId(request.getLineId());
                if (Objects.isNull(linePayDO)) {
                    throw new ServiceException(ErrorCodeEnum.LINE_PAY_FALSE);
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String dateString = sdf.format(linePayDO.getPayTime());
                franchiseeDO.setPayDateStr(dateString);
                franchiseeDO.setRetAccount(ReceivingBankEnum.XFSG_RECEIVING_BANK.getAccountNum());
                franchiseeDO.setBank(linePayDO.getBankCode());
                franchiseeDO.setBankSub(linePayDO.getBranchBankCode());
                //查城市信息
                LineInfoDO lineInfoDO = lineInfoMapper.getByLineId(request.getLineId());
                if (Objects.isNull(lineInfoDO)) {
                    throw new ServiceException(ErrorCodeEnum.LINE_ID_IS_NOT_EXIST);
                }
                if (StringUtil.isNotBlank(lineInfoDO.getPartnerNum())) {
                    throw new ServiceException(ErrorCodeEnum.DUPLICATE_SUBMISSION);
                }
                if (lineInfoDO.getPartnerNum() != null) {
                    return new ResponseResult(200000, null, null);
                }
                if ("1".equals(lineInfoDO.getSex())) {
                    franchiseeDO.setSex(1);
                } else if ("2".equals(lineInfoDO.getSex())) {
                    franchiseeDO.setSex(0);
                }
                HyOpenAreaInfoDO openAreaInfoDO = openAreaInfoMapper.selectById(lineInfoDO.getWantShopAreaId());
                franchiseeDO.setProvinceCode(String.valueOf(openAreaInfoDO.getParentId()));
                franchiseeDO.setCityCode(String.valueOf(openAreaInfoDO.getId()));
                franchiseeDO.setOperator(user.getJobNumber());
                MemberQuestionDO memberQuestionDO = joinIntentionMapper.getByLineId(lineInfoDO.getId());
                //如果是企业加盟，需要传有效期和法人
                if (Objects.nonNull(memberQuestionDO) && Constants.TWO_INTEGER.equals(memberQuestionDO.getJoinType())) {
                    SigningBaseInfoDO signingBaseInfoDO = intentAgreementMapper.selectByPartnerIdOrLineId(null, lineInfoDO.getId());
                    BusinessLicenseInfoVO businessLicenseInfo = aliyunService.getBusinessLicenseInfo(signingBaseInfoDO.getBusinessLicense());
                    franchiseeDO.setBusinessTerm(businessLicenseInfo.getValidPeriod());
                    franchiseeDO.setLegalPerson(businessLicenseInfo.getLegalPerson());
                }
                InitiatingResponse initiatingResponse = httpRestTemplateService.postForObject(url, franchiseeDO, InitiatingResponse.class);
                //更新线索(进入蓄水池并回填加盟商编码)
                if (initiatingResponse.getCode() == 0) {
                    LineInfoDO lineInfoParam = new LineInfoDO();
                    lineInfoParam.setId(request.getLineId());
                    //蓄水池
                    lineInfoParam.setJoinStatus(1);
                    lineInfoParam.setPartnerNum(initiatingResponse.getData());
                    lineInfoMapper.updateByPrimaryKeySelective(lineInfoParam);
                }
                if (initiatingResponse.getCode() != 0) {
                    lineInfoDO.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_63.getCode());
                    lineInfoMapper.updateByPrimaryKeySelective(lineInfoDO);
                    return new ResponseResult(500, initiatingResponse.getMessage(), initiatingResponse.getData());
                } else {
                    return new ResponseResult(200000, initiatingResponse.getMessage(), initiatingResponse.getData());
                }
            } else {
                throw new ServiceException(ErrorCodeEnum.DUPLICATE_SUBMISSION);
            }
        } finally {
            if (Boolean.TRUE.equals(acquired)) {
                String currentValue = redisUtilPool.getString(lockKey);
                if (lockValue.equals(currentValue)) {
                    redisUtilPool.delKey(lockKey);
                }
            }
        }
    }

    @Override
    public Boolean auditResult(AuditResultRequest request) {
        String kdzBusinessId = request.getKdzBusinessId();
        String lineId = getLineId(kdzBusinessId);
        String redisKey = "kdzBusinessId:" + kdzBusinessId;
        if (StringUtil.isBlank(lineId)) {
            throw new ServiceException(ErrorCodeEnum.BUSINESS_ID_NOT_EXIST);
        }
        LineInfoDO lineInfoDO = lineInfoMapper.getByLineId(Long.valueOf(lineId));
        if (Objects.isNull(lineInfoDO)) {
            throw new ServiceException(ErrorCodeEnum.LINE_ID_IS_NOT_EXIST);
        }
        String auditResult = redisUtilPool.getString(redisKey);
        if (WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_70.getCode().equals(lineInfoDO.getWorkflowSubStageStatus())) {
            //鲜丰系统不稳定，会出现调用成功但内部状态未更改的情况，这时直接返回true即可
            return true;
        }
        if (request.getAuditResult() == 1) {
            AuditPassRequest auditPassRequest = new AuditPassRequest();
            auditPassRequest.setLineId(lineInfoDO.getId());
            auditPassRequest.setPassReason(request.getCause());
            auditPassRequest.setWorkflowSubStage(lineInfoDO.getWorkflowSubStage());
            commonService.getLineFlowService(auditPassRequest.getWorkflowSubStage()).auditPass(auditPassRequest, null);
        } else if (request.getAuditResult() == 0) {
            AuditRejectRequest auditRejectRequest = new AuditRejectRequest();
            auditRejectRequest.setLineId(lineInfoDO.getId());
            auditRejectRequest.setWorkflowSubStage(lineInfoDO.getWorkflowSubStage());
            auditRejectRequest.setRejectPublicReason(request.getCause());
            auditRejectRequest.setRejectRealReason(request.getFailureCause());
            commonService.getLineFlowService(auditRejectRequest.getWorkflowSubStage()).auditReject(auditRejectRequest, null);
        }
        redisUtilPool.setString(redisKey, JSONObject.toJSONString(request.getAuditResult()));
        return true;
    }

    private String getLineId(String kdzBusinessId) {
        return kdzBusinessId.substring(kdzBusinessId.indexOf("_") + 1, kdzBusinessId.lastIndexOf("_"));
    }

    private void fillSignatureInfo(Map<String, Object> requestMap) {
        long timestamp = System.currentTimeMillis();
        String signature = SecureUtil.getSignature(timestamp);
        requestMap.put("timestamp", timestamp);
        requestMap.put("signature", signature);
    }
}
