package com.jeequan.jeepay.pay.service.openapi.impl;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.converter.MchInfoConverter;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchAlipayConfigService;
import com.jeequan.jeepay.core.interfaces.paychannel.IIsvmchWxConfigService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.DBApplicationConfig;
import com.jeequan.jeepay.core.model.applyment.ApplymentSignInfo;
import com.jeequan.jeepay.core.model.openapi.AccessReq;
import com.jeequan.jeepay.core.model.openapi.biz.AuditResultResp;
import com.jeequan.jeepay.core.model.openapi.biz.income.AuditH5;
import com.jeequan.jeepay.core.model.openapi.biz.income.AuditH5Resp;
import com.jeequan.jeepay.core.model.openapi.biz.income.QueryApplyment;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.service.impl.*;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * TODO
 *
 * @author deng
 * @since 2024/4/19
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MchApplymentApiService {

    private final MchAppService mchAppService;
    private final MchInfoService mchInfoService;
    private final SysUserService sysUserService;
    private final SysConfigService sysConfigService;
    private final SysUserAuthService sysUserAuthService;
    private final MchApplymentService mchApplymentService;
    private final IsvUserConnService isvUserConnService;
    private final PayInterfaceConfigService payInterfaceConfigService;
    private final IsvInfoService isvInfoService;
    private final MchInfoConverter mchInfoConverter;
    private final MchStoreService mchStoreService;

    @Transactional(rollbackFor = Exception.class)
    public Object createH5MchApplyment(AccessReq request) {
        MchApp appInfo = request.getAppInfo();
        MchInfo mchInfo = mchInfoService.getById(appInfo.getMchNo());

        AuditH5 bizData = request.getBizDataJSON().toJavaObject(AuditH5.class);
        String range = bizData.getRange();

        Assert.notNull(bizData, "缺少业务参数");

        String subApplyId = bizData.getApplicationId();
        Assert.notNull(subApplyId, "申请单号不能为空");

        MchApplyment existData = mchApplymentService.getBySubApplyId(subApplyId);
        MchApplyment mchApplyment;

        AuditH5Resp resp = new AuditH5Resp();

        DBApplicationConfig dbApplicationConfig = sysConfigService.getDBApplicationConfig();
//        dbApplicationConfig.setMchSiteUrl("http://127.0.0.1:9218");
        String token = getToken(appInfo, dbApplicationConfig);

        if (existData != null) {
            if (!Objects.equals(existData.getAutoConfigMchAppId(), appInfo.getAppId())) {
                throw new BizException("应用ID与进件申请单号不匹配");
            }

            mchApplyment = existData;
        } else {
            Assert.notNull(bizData.getIfCode(), "通道类型不能为空");

            Assert.notNull(CS.IfCode.get(bizData.getIfCode()), "未知的通道类型");

            IsvInfoEntity isvInfo = isvInfoService.getById(bizData.getIsvNo());
            Assert.notNull(isvInfo, "无效的渠道编码");

            IsvUserConnEntity connInfo = isvUserConnService.get(CS.SYS_ROLE_TYPE.MCH, mchInfo.getMchNo(), bizData.getIsvNo());
            Assert.notNull(connInfo, "无效的渠道编码");
            Assert.isTrue(Objects.equals(connInfo.getStatus(), (int) CS.YES), "无效的渠道编码");

            PayInterfaceConfig payInterfaceConfig = payInterfaceConfigService.getByInfoIdAndIfCode(CS.SYS_ROLE_TYPE.ISV, bizData.getIsvNo(), bizData.getIfCode());
            String channelTypes = payInterfaceConfig.getChannelTypes();
            if (range.equals("0") && !channelTypes.contains("1")) {
                // 线下费率不存在
                throw new BizException("当前所选渠道通道不支持线下");
            }

            if (range.equals("1") && !channelTypes.contains("2")) {
                // 线上费率不存在
                throw new BizException("当前所选渠道通道不支持线上");
            }

            mchApplyment = new MchApplyment();
            mchApplyment.setIfCode(bizData.getIfCode());
            mchApplyment.setAutoConfigMchAppId(appInfo.getAppId());
            mchApplyment.setAgentNo(mchInfo.getAgentNo());
            mchApplyment.setIsvNo(bizData.getIsvNo());
            mchApplyment.setSubApplyId(bizData.getApplicationId());
            mchApplyment.setMchNo(mchInfo.getMchNo());
            mchApplyment.setApplyId(SeqKit.genMchApplyNo());
            mchApplyment.setApplyDetailInfo("{}");
            mchApplyment.setNotifyUrl(bizData.getNotifyUrl());
            mchApplyment.setState(com.jeequan.jeepay.core.entity.MchApplyment.STATE_SAVE);

            mchApplymentService.save(mchApplyment);
        }

        resp.setAppId(appInfo.getAppId());
        resp.setIfCode(mchApplyment.getIfCode());
        resp.setIsvNo(mchInfo.getIsvNo());
        resp.setAppId(mchApplyment.getAutoConfigMchAppId());
        resp.setApplyId(mchApplyment.getApplyId());
        resp.setDetailH5Url(mchApplyment.getApplyId());

        String h5DetailUrl = getH5DetailUrl(dbApplicationConfig.getMchSiteUrl(), token, mchApplyment, appInfo);
        Map<String, Object> result = new HashMap<>();
        result.put("url", h5DetailUrl);
        result.put("applyId", mchApplyment.getApplyId());
        result.put("subApplyId", mchApplyment.getSubApplyId());

        return result;
    }

    public Object queryApplymentInfo(AccessReq request) {
        QueryApplyment bizData = request.getBizDataJSON().toJavaObject(QueryApplyment.class);

        String applicationId = bizData.getApplicationId();
        String applyId = bizData.getApplyId();

        if (ObjUtil.isEmpty(applyId) && ObjUtil.isEmpty(applicationId)) {
            throw new BizException("【applyId】和【applicationId】不可同时为空");
        }

        MchApplyment mchApplyment = mchApplymentService.lambdaQuery()
                .eq(!ObjUtil.isEmpty(applyId), MchApplyment::getApplyId, applyId)
                .eq(!ObjUtil.isEmpty(applicationId), MchApplyment::getSubApplyId, applicationId)
                .one();

        Assert.notNull(mchApplyment, "未获取到商户信息");

        com.jeequan.jeepay.core.entity.MchApplyment model = mchInfoConverter.toModel(mchApplyment);

        AuditResultResp auditResultResp = new AuditResultResp(model);

        IIsvmchAlipayConfigService alipayConfigService = SpringBeansUtil.getBean(mchApplyment.getIfCode() + "IsvmchAlipayConfigService", IIsvmchAlipayConfigService.class);
        IIsvmchWxConfigService wxConfigService = SpringBeansUtil.getBean(mchApplyment.getIfCode() + "IsvmchWxConfigService", IIsvmchWxConfigService.class);

        if (model.getState() == com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS
            || model.getState() == com.jeequan.jeepay.core.entity.MchApplyment.STATE_SUCCESS_NEED_SECOND_VERIFY) {
            if (alipayConfigService != null) {
                ApplymentSignInfo alipayOpenSignInfo = alipayConfigService.alipayOpenSignInfo(model);
                auditResultResp.setZfbInfo(alipayOpenSignInfo);
            }

            if (wxConfigService != null) {
                ApplymentSignInfo wxOpenSignInfo = wxConfigService.wxOpenSignInfo(model);
                auditResultResp.setWxInfo(wxOpenSignInfo);
            }
        }


        MchStore mchStore = mchStoreService.getByMchApplyId(mchApplyment.getApplyId());
        if (mchStore != null) {
            auditResultResp.setMchStore(mchInfoConverter.toModel(mchStore));
        }

        return auditResultResp;
    }

    private String getH5DetailUrl(String mchDomainUrl, String token, MchApplyment mchApplyment, MchApp mchApp) {
        return mchDomainUrl + "/h5MchApplyment?" + "isView=0" + "&jeepayToken=" + token + "&applyId=" + mchApplyment.getApplyId()
                + "&isvNo=" + mchApplyment.getIsvNo() + "&mchNo=" + mchApplyment.getMchNo() + "&range=" + mchApp.getRange();
    }

    private String getToken(MchApp appInfo, DBApplicationConfig dbApplicationConfig) {
        MchAppEntity mchApp = mchAppService.getById(appInfo.getAppId());
        MchInfo mchInfo = mchInfoService.getById(mchApp.getMchNo());

        SysUserEntity sysUser = sysUserService.getById(mchInfo.getInitUserId());
        SysUserAuth sysUserAuth = sysUserAuthService.lambdaQuery()
                .eq(SysUserAuth::getIdentifier, sysUser.getLoginUsername())
                .eq(SysUserAuth::getSysType, CS.SYS_ROLE_TYPE.MCH)
                .one();

        String accessUrl = dbApplicationConfig.getMchSiteUrl() + "/api/anon/auth/privateValidate";

        HttpRequest httpRequest = HttpUtil.createPost(accessUrl);
        @Cleanup HttpResponse response = httpRequest.form("loginName", sysUserAuth.getIdentifier())
                .form("pwd", sysUserAuth.getCredential())
                .execute();

        String body = response.body();

        ApiRes apiRes = JSON.parseObject(body, ApiRes.class);

        return ((String) apiRes.getData());
    }
}
