package cn.pluss.platform.task;

import cn.pluss.platform.BankCardService;
import cn.pluss.platform.MerchantAuditRecordService;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.mapper.*;
import cn.pluss.platform.merchant.AccountService;
import cn.pluss.platform.merchant.MerchantCashPlaceService;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.notice.NoticeService;
import cn.pluss.platform.subMerchant.SubMerchantService;
import cn.pluss.platform.suixingfu.SxfConstants;
import cn.pluss.platform.user.impl.GeneralPushUtil;
import cn.pluss.platform.util.IpUtils;
import cn.pluss.platform.util.LogExceptionUtils;
import cn.pluss.platform.wx.WxCertService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Date;
import java.util.Map;

/**
 * @author djh
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class SxfMerAuditHandler {

    @Setter(onMethod_ = {@Lazy, @Autowired})
    private MerchantChannelStatusMapper mcsMapper;
    @Setter(onMethod_ = {@Lazy, @Autowired})
    private WxCertService wxCertService;
    @Setter(onMethod_ = {@Lazy, @Autowired})
    private MerchantBaseInfoService merchantBaseInfoService;
    @Setter(onMethod_ = {@Autowired})
    private MerchantAuditRecordService merchantAuditRecordService;

    @Setter(onMethod_ = {@Autowired})
    private BankCardService bankCardService;

    @Autowired
    private AccountService accountService;

    private final RestTemplate restTemplate;

    @Setter(onMethod_ = {@Autowired})
    private NoticeService noticeService;

    @Setter(onMethod_ = {@Autowired, @Lazy})
    private MerchantCashPlaceService cashPlaceService;

    private final NoticeMapper noticeMapper;
    private final UserAppMapper userAppMapper;
    private final UserInfoMapper userInfoMapper;
    private final MerchantStoreMapper merchantStoreMapper;
    private final MerchantImageMapper merchantImageMapper;
    private final MercIncomSetRateHandler mercIncomSetRateHandler;

    @Autowired
    private GeneralPushUtil generalPushUtil;


    @Autowired
    private SubMerchantService subMerchantService;

    @Autowired
    @Lazy
    private SxfMerAuditHandler self;

    @Async
    public void auditHandler(JSONObject auditResult) {
        execute(auditResult);
    }

    /**
     * 操作
     */
    public void execute(JSONObject auditResult) {
        MerchantChannelStatus mcs = self.auditCallback(auditResult);

        try {
            log.info("===================>进件回调，创建店铺开始,商户编号mno为:{}<=====================", auditResult.getString("mno"));
            self.createStore(mcs);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("创建店铺信息异常,异常信息:{}", e.getMessage());
        }

        try {
            MerchantBaseInfo merchantBaseInfo = merchantBaseInfoService.getMerchantBaseInfoByMerchantCode(mcs.getMerchantCode());
            if (StringUtils.isNotBlank(merchantBaseInfo.getUserId())) {
                cashPlaceService.createDefaultCashPlace(Long.parseLong(merchantBaseInfo.getUserId()));
            }
        } catch (Exception e) {
            LogExceptionUtils.printStack(log, e, "创建默认收银点失败,异常信息:{}");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public MerchantChannelStatus auditCallback(JSONObject auditResult) {
        MerchantChannelStatus merchantChannelStatus = new MerchantChannelStatus()
                .setChannel(1)
                .setApplicationId(auditResult.getString("applicationId"))
                .setMerchantId(auditResult.getString("mno"));
        merchantChannelStatus = mcsMapper.selectOne(new QueryWrapper<>(merchantChannelStatus));

        String taskStatus = auditResult.getString("taskStatus");

        merchantChannelStatus.setThirdStatus(taskStatus);
        // 秒审通过
        auditFirstTrialSuccess(merchantChannelStatus, auditResult);
        // 终审通过
        auditSuccess(merchantChannelStatus, auditResult);
        // 入驻驳回
        auditReject(merchantChannelStatus, auditResult);
        // 入驻图片驳回
        auditImageReject(merchantChannelStatus, auditResult);

        MerchantAuditRecord lastRecord = merchantAuditRecordService.getLastRecord(merchantChannelStatus.getMerchantCode());
        if (lastRecord != null) {
            lastRecord.setStatus(merchantChannelStatus.getStatus());
            lastRecord.setThirdStatus(merchantChannelStatus.getThirdStatus());
            lastRecord.setRemark(auditResult.getString("suggestion"));
            merchantAuditRecordService.updateById(lastRecord);
        }

        return merchantChannelStatus;
    }

    /**
     * 只处理秒审通过
     */
    private void auditFirstTrialSuccess(MerchantChannelStatus merchantChannelStatus, JSONObject auditResult) {
        // 不属于这个状态的不处理
        String taskStatus = auditResult.getString("taskStatus");

        if (!SxfConstants.AUDIT_TASK_STATUS_FIRST_TRIAL_SUCCESS.equals(taskStatus)) {
            return;
        }

        JSONArray repoInfo = auditResult.getJSONArray("repoInfo");

        // 入驻信息可能发生变化，需要监听是否发出微信认证请求
        wxCert(auditResult.getJSONArray("repoInfo"), merchantChannelStatus);

        // 已秒审通过状态，则不需要改变当前信息状态
        if (MerchantChannelStatus.AUDIT_STATUS_FIRST_TRIAL_SUCCESS.equals(merchantChannelStatus.getStatus())) {
            return;
        }

        merchantChannelStatus.setUpdateTime(new Date());

        merchantChannelStatus.setCallbackStatus("1");
        merchantChannelStatus.setStatus(MerchantChannelStatus.AUDIT_STATUS_FIRST_TRIAL_SUCCESS);
        merchantChannelStatus.setRemark(auditResult.getString("suggestion"));
        mcsMapper.updateById(merchantChannelStatus);

        UserApp userApp = userAppMapper.selectByMerchantCode(merchantChannelStatus.getMerchantCode());
        String pushMsg = "商家秒审通过，已可使用秒审额度收款！等待人工复审中！";
        Notice notice = new Notice(1, 1, userApp);
        notice.setNoticeCode(auditResult.getString("applicationId"));
        notice.setUniqueKey(auditResult.getString("applicationId") + "_" + auditResult.getString("timeStamp"));
        notice.setCreateDt(new Date());
        notice.setConrtent(pushMsg);
        noticeMapper.insert(notice);
        generalPushUtil.sendAllPlatByAlias(Collections.singletonList(userApp.getUserId() + ""), "商家审核通知", pushMsg, "1");
    }

    /**
     * 终审通过
     */
    private void auditSuccess(MerchantChannelStatus merchantChannelStatus, JSONObject auditResult) {
        // 不属于这个状态的不处理
        String taskStatus = auditResult.getString("taskStatus");
        // 校验随行付回调状态
        if (!SxfConstants.AUDIT_TASK_STATUS_SUCCESS.equals(taskStatus)) {
            return;
        }

        wxCert(auditResult.getJSONArray("repoInfo"), merchantChannelStatus);

        // 已终审
        if (MerchantChannelStatus.AUDIT_STATUS_SUCCESS.equals(merchantChannelStatus.getStatus())
                || MerchantChannelStatus.AUDIT_STATUS_DATA_EDIT.equals(merchantChannelStatus.getStatus())) {
            // 变更银行卡后(非常！！！可能)也会走该回调。
            return;
        }

        log.info("审核通过");
        UserApp userApp = userAppMapper.selectByMerchantCode(merchantChannelStatus.getMerchantCode());
        merchantChannelStatus.setCallbackStatus("1");
        merchantChannelStatus.setStatus(MerchantChannelStatus.AUDIT_STATUS_SUCCESS);
        merchantChannelStatus.setUpdateTime(new Date());
        merchantChannelStatus.setRemark(auditResult.getString("suggestion"));
        String pushMsg = "商家审核通过";

        String uniqueKey = auditResult.getString("applicationId") + System.currentTimeMillis();
        sendNotice(userApp, "收银呗审核通知", pushMsg, uniqueKey);
        mcsMapper.updateById(merchantChannelStatus);

        //TODO 统计当前进件商户的上级商户是否满足费率要求
        try {
            mercIncomSetRateHandler.installSuperMerchantRate(userApp);
        } catch (Exception e) {
            log.info("设置进件商户上级商户费率异常，异常信息:{}", e.getMessage());
        }
    }

    /**
     * 人工审核-入驻驳回
     */
    private void auditReject(MerchantChannelStatus merchantChannelStatus, JSONObject auditResult) {
        String taskStatus = auditResult.getString("taskStatus");
        if (!SxfConstants.AUDIT_TASK_STATUS_REJECT.equals(taskStatus)) {
            return;
        }

        // 入驻驳回
        if (MerchantChannelStatus.AUDIT_STATUS_REJECT.equals(merchantChannelStatus.getStatus())) {
            return;
        }

        log.info("人工审核-入驻驳回");
        UserApp userApp = userAppMapper.selectByMerchantCode(merchantChannelStatus.getMerchantCode());
        merchantChannelStatus.setCallbackStatus("1");
        merchantChannelStatus.setStatus(MerchantChannelStatus.AUDIT_STATUS_REJECT);
        merchantChannelStatus.setUpdateTime(new Date());
        String pushMsg = auditResult.getString("suggestion");
        merchantChannelStatus.setRemark(auditResult.getString("suggestion"));

        String uniqueKey = auditResult.getString("applicationId") + "_" + auditResult.getString("timeStamp");
        sendNotice(userApp, "收银呗审核通知", pushMsg, uniqueKey);
        mcsMapper.updateById(merchantChannelStatus);
    }

    /**
     * 复审驳回
     */
    private void auditImageReject(MerchantChannelStatus merchantChannelStatus, JSONObject auditResult) {
        String taskStatus = auditResult.getString("taskStatus");
        if (!SxfConstants.AUDIT_TASK_STATUS_IMAGE_REJECT.equals(taskStatus)) {
            return;
        }

        // 秒审通过-复审驳回
        if (MerchantChannelStatus.AUDIT_STATUS_REVIEW_REJECT.equals(merchantChannelStatus.getStatus())) {
            return;
        }

        log.info("秒审通过-复审驳回");
        UserApp userApp = userAppMapper.selectByMerchantCode(merchantChannelStatus.getMerchantCode());
        merchantChannelStatus.setCallbackStatus("1");
        merchantChannelStatus.setStatus(MerchantChannelStatus.AUDIT_STATUS_REVIEW_REJECT);
        merchantChannelStatus.setUpdateTime(new Date());

        String pushMsg = auditResult.getString("suggestion");
        merchantChannelStatus.setRemark(pushMsg);
        String uniqueKey = auditResult.getString("applicationId") + "_" + auditResult.getString("timeStamp");
        sendNotice(userApp, "收银呗审核通知", pushMsg, uniqueKey);
        mcsMapper.updateById(merchantChannelStatus);
    }

    /**
     * 微信认证
     *
     * @param repoInfo 报备信息
     *                 [{
     *                 “repoStatus”: “01”,
     *                 “childNoType”: “WX”,
     *                 “childNo”: “225505167”,
     *                 “channelId”: “211234567”
     *                 }]
     */
    private void wxCert(JSONArray repoInfo, MerchantChannelStatus mcs) {
        if (repoInfo == null) {
            return;
        }

        for (int i = 0; i < repoInfo.size(); i++) {
            JSONObject o = repoInfo.getJSONObject(i);

            try {
                SubMerchant subMerchant = new SubMerchant();
                subMerchant.setSubMchType(o.getString("childNoType"));
                subMerchant.setMerchantId(mcs.getMerchantId());
                subMerchant.setStatus(o.getString("repoStatus"));
                subMerchant.setChannelId(o.getString("channelId"));
                subMerchant.setChannelTypeId("1");
                subMerchant.setSubMchId(o.getString("childNo"));

                SubMerchant exist = new SubMerchant();
                exist.setSubMchType(o.getString("childNoType"));
                exist.setMerchantId(mcs.getMerchantId());
                exist.setChannelTypeId("1");
                exist = subMerchantService.getOne(new QueryWrapper<>(exist).last("limit 1"));
                if (exist != null) {
                    subMerchant.setId(exist.getId());
                    subMerchantService.updateById(subMerchant);
                } else {
                    subMerchantService.save(subMerchant);
                }
            } catch (Exception e) {
                log.warn("子商户信息保存失败");
            }


            // 报备成功的微信子商户号才进行微信认证
            if (!"WX".equals(o.getString("childNoType")) || "02".equals(o.getString("repoStatus"))) {
                continue;
            }

            try {
                wxCertService.wxCert(mcs.getMerchantId(), mcs.getMerchantCode(), 1);
            } catch (Exception e) {
                log.info("============>微信实名认证异常,异常商户编号:{},异常信息:{}\n<==================", mcs.getMerchantCode(), e.toString());
            }

            break;
        }
    }

    public void createStore(MerchantChannelStatus merchantChannelStatus) {
//        if (!"4".equals(merchantChannelStatus.getStatus()) && !"3".equals(merchantChannelStatus.getStatus())) {
//            return;
//        }
        UserApp userApp = userAppMapper.selectByMerchantCode(merchantChannelStatus.getMerchantCode());
        UserInfo userInfo = userInfoMapper.selectById(userApp.getUserId());
        log.info("==============>当前需要同步的用户进件数据为：:{}<===================", JSONObject.toJSONString(merchantChannelStatus));
        if (userInfo != null) {
            MerchantStore merchantStore = new MerchantStore().setMerchantCode(merchantChannelStatus.getMerchantCode());
            merchantStore = merchantStoreMapper.selectOne(new QueryWrapper<>(merchantStore));
            MerchantBaseInfo merchantBaseInfo = merchantBaseInfoService.getMerchantBaseInfoByMerchantCode(merchantChannelStatus.getMerchantCode());
            QueryWrapper<MerchantImage> queryWrapper = new QueryWrapper<MerchantImage>()
                    .eq("merchantCode", merchantChannelStatus.getMerchantCode()).eq("photoType", "06");
            MerchantImage merchantImage = merchantImageMapper.selectOne(queryWrapper);
            String baseUrl = "https://life.sxczgkj.cn/web/wmerchant.php?c=site&a=entry&ctrl=store&ac=oauth&op=add_merchan&do=web&m=we7_wmall&i=1";
            StringBuilder sb = new StringBuilder(baseUrl);
            sb.append("&title=").append(merchantBaseInfo.getAlias());
            sb.append("&password=").append(userInfo.getPassword().toLowerCase());
            sb.append("&mobile=").append(userInfo.getLoginName());
            sb.append("&syb_m_id=").append(merchantStore.getId());
            sb.append("&addressNo=").append(merchantBaseInfo.getAddressNo());
            String address = merchantBaseInfo.getProvince() + merchantBaseInfo.getCity() + merchantBaseInfo.getDistrict() + merchantBaseInfo.getAddress();
            String area = merchantBaseInfo.getProvince() +"-"+ merchantBaseInfo.getCity() +"-"+ merchantBaseInfo.getDistrict();
            try {
                String decodeAddress = URLEncoder.encode(address, "UTF-8");
                sb.append("&address=").append(decodeAddress);
                String decodeArea = URLEncoder.encode(area, "UTF-8");
                sb.append("&area=").append(decodeArea);
                String logo = URLEncoder.encode(merchantImage.getPicUrl(), "GBK");
                sb.append("&logo=").append(logo);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                log.error("=============>请求生成店铺logo门头照转码异常,异常信息:{}<===============", e.getMessage());
            }
            Map<String, String> lnxMap = IpUtils.getLocationByAddress(address);
            if (lnxMap != null) {
                sb.append("&location_x=").append(lnxMap.get("x"));
                sb.append("&location_y=").append(lnxMap.get("y"));
            }
            // 请求生成店铺j
            String result = restTemplate.getForObject(sb.toString(), String.class);
            log.info("=============>请求生成店铺URL：{}，请求响应返回的参数为:{}<===============", sb.toString(), result);
        }
    }

    /**
     * 商户信息修改回调
     *
     * @param auditResult
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void auditEditHandler(JSONObject auditResult) {
        // 商户信息修改结果状态
        String taskStatus = auditResult.getString("taskStatus");
        // 商户信息修改工单号
        String applicationId = auditResult.getString("applicationId");

        String timeStamp = auditResult.getString("timeStamp");

        String remark = auditResult.getString("suggestion");

        MerchantAuditRecord auditRecord = new MerchantAuditRecord();
        auditRecord.setChannel(1);
        auditRecord.setApplicationId(applicationId);
        auditRecord = merchantAuditRecordService.getOne(new QueryWrapper<>(auditRecord));
        if (auditRecord == null) {
            log.error("未查询到对应的工单信息");
            return;
        }

        auditRecord.setRemark(remark);
        auditRecord.setThirdStatus(taskStatus);
        UpdateWrapper<MerchantAuditRecord> wrapper = new UpdateWrapper<>();
        wrapper.eq("applicationId", applicationId);
        merchantAuditRecordService.update(auditRecord, wrapper);

        MerchantChannelStatus channelStatus = new MerchantChannelStatus();
        channelStatus.setStatus("3");
        UpdateWrapper<MerchantChannelStatus> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("merchantCode", auditRecord.getMerchantCode())
                .eq("channel", 1);

        String merchantCode = auditRecord.getMerchantCode();
        UserApp userApp = new UserApp().setMerchantCode(merchantCode).setUserType("promoter");
        userApp = userAppMapper.selectOne(new QueryWrapper<>(userApp));

        Account account = new Account().setUserId(userApp.getUserId() + "");
        account = accountService.getOne(new QueryWrapper<>(account));


        if (SxfConstants.AUDIT_TASK_STATUS_EDIT_SUCCESS.equals(taskStatus)) {
            // 修改后的银行卡信息
            JSONObject bak = account.getBak();
            BankCard newBankCard = JSONObject.toJavaObject(bak, BankCard.class);
            newBankCard.setAccountType(BankCard.ACCOUNT_TYPE_PRIVATE);
            account.setBak(null);
            int count = accountService.count(new QueryWrapper<Account>().eq("bankCardId", account.getBankCardId()));
            if (count == 1) {
                newBankCard.setId(Integer.parseInt(account.getBankCardId()));
                bankCardService.updateById(newBankCard);
            } else {
                bankCardService.save(newBankCard);
                account.setBankCardId(newBankCard.getId() + "");
                accountService.updateById(account);
            }

            // 商户修改通过后，修改为最新的业务id
            channelStatus.setApplicationId(applicationId);

            mcsMapper.update(channelStatus, updateWrapper);

            MerchantBaseInfo mbi = merchantBaseInfoService.getMerchantBaseInfoByMerchantCode(merchantCode);

            noticeService.sendEditApplySuccessNotice(userApp.getUserId() + "", mbi.getAlias(), "次日到账");

//            sendNotice(userApp, "结算账户修改通知", "结算账户修改成功", applicationId + "_" + timeStamp);
        }

        if (SxfConstants.AUDIT_TASK_STATUS_EDIT_FAIL.equals(taskStatus)) {
            // 修改失败
            channelStatus.setStatus(MerchantChannelStatus.AUDIT_STATUS_SUCCESS);
            mcsMapper.updateById(channelStatus);

            sendNotice(userApp, "结算账户修改通知", "结算账户修改失败: " + auditResult.getString("suggestion"), applicationId + "_" + timeStamp);
        }

    }

    /**
     * 发送通知及推送
     * @param userApp    用户id
     * @param title     标题
     * @param msg       内容
     * @param uniqueKey 唯一key
     */
    public void sendNotice(UserApp userApp, String title, String msg, String uniqueKey) {
        Notice notice = new Notice(1, 1, userApp);
        notice.setNoticeCode(uniqueKey);
        notice.setConrtent(msg);
        noticeService.saveMerAuthNotice(notice);

        generalPushUtil.sendAllPlatByAlias(Collections.singletonList(userApp.getUserId() + ""), title, msg, "1");
    }

    /**
     * 发送通知及推送
     * @param userId    用户id
     * @param title     标题
     * @param msg       内容
     * @param uniqueKey 唯一key
     */
    public void sendNotice(String userId, String title, String msg, String uniqueKey) {
        Notice notice = new Notice(1, 1, userId);
        notice.setNoticeCode(uniqueKey);
        notice.setConrtent(msg);
        noticeService.saveMerAuthNotice(notice);

        generalPushUtil.sendAllPlatByAlias(Collections.singletonList(userId + ""), title, msg, "1");
    }

}
