package com.zhongshu.card.server.core.service.pay;

import com.github.microservice.auth.security.helper.AuthHelper;
import com.github.microservice.core.util.JsonUtil;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerModel;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerTreeModel;
import com.github.microservice.pay.client.ret.ResultState;
import com.github.microservice.pay.client.service.ledger.GeneralLedgerService;
import com.github.microservice.types.payment.PaymentChannelType;
import com.zhongshu.card.client.type.payAccount.PayAccountLevel;
import com.zhongshu.card.server.core.dao.pay.PayAccountDao;
import com.zhongshu.card.server.core.domain.pay.PayAccount;
import com.zhongshu.card.server.core.service.paySetting.ProjectPaySettingServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
@Slf4j
public class PayAccountService {

    @Autowired
    ProjectPaySettingServiceImpl projectPaySettingService;

    @Autowired
    PayAccountDao payAccountDao;

    @Autowired
    AuthHelper authHelper;

    @Autowired
    GeneralLedgerService generalLedgerService;

    /**
     * 获取项目总账户
     */
    public PayAccount getProjectParent(String projectOid){
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndLevel(projectOid, PayAccountLevel.projectParent);
        if (payAccount==null){
            payAccount = createProjectParentAccount(projectOid);
        }
        return payAccount;
    }

    /**
     * 获取项目子账户
     */
    @SneakyThrows
    public PayAccount getProjectChildren(String projectOid, PaymentChannelType channelType){
        PayAccount parent = getProjectParent(projectOid);
        if (parent==null){
            throw new Exception("获取项目总账户失败");
        }
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndLevelAndPaymentChannelType(projectOid, PayAccountLevel.projectChildren, channelType);
        if (payAccount==null){
            payAccount = createProjectChildrenAccount(projectOid, channelType, parent);
        }
        return payAccount;
    }

    /**
     * 获取用户总账户
     */
    public PayAccount getUserParent(String projectOid, String userId){
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndUserIdAndLevel(projectOid, userId, PayAccountLevel.UserParent);
        if (payAccount==null){
            payAccount = createUserParentAccount(projectOid, userId);
        }
        return payAccount;
    }


    /**
     * 获取用户子账户
     */
    @SneakyThrows
    public PayAccount getUserChildren(String projectOid, String userId, PaymentChannelType channelType){
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndUserIdAndLevelAndPaymentChannelType(projectOid, userId, PayAccountLevel.UserChildren, channelType);
        if (payAccount==null){
            PayAccount parent = getUserParent(projectOid, userId);
            if (parent==null){
                throw new Exception("获取用户总账户失败");
            }
            payAccount = createUserChildrenAccount(projectOid, userId, channelType, parent);
        }
        return payAccount;
    }

    /**
     * 获取机构总账户
     * @return
     */
    public PayAccount getOrgParent(String projectOid, String oid){
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndOidAndLevel(projectOid, oid, PayAccountLevel.OrgParent);
        if (payAccount==null){
            payAccount = createOrgParentAccount(projectOid, oid);
        }
        return payAccount;
    }

    /**
     * 获取机构子账户
     * @return
     */
    @SneakyThrows
    public PayAccount getOrgChildren(String projectOid, String oid, PaymentChannelType channelType){
        PayAccount payAccount = payAccountDao.findTopByProjectOidAndOidAndLevelAndPaymentChannelType(projectOid, oid,PayAccountLevel.OrgChildren, channelType);
        if (payAccount==null){
            PayAccount parent = getOrgParent(projectOid, oid);
            if (parent==null){
                throw new Exception("获取机构总账户失败");
            }
            payAccount = createOrgChildrenAccount(projectOid, oid, channelType, parent);
        }
        return payAccount;
    }

    @SneakyThrows
    private PayAccount createOrgChildrenAccount(String projectOid, String oid, PaymentChannelType channelType, PayAccount parent) {
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setParent(parent);
        payAccount.setOid(oid);
        payAccount.setPaymentChannelType(channelType);
        payAccount.setLevel(PayAccountLevel.OrgChildren);
        String ledgerId = createLedger(new String[]{projectOid, oid}, "机构子账-" + channelType.getRemark(),
                parent.getLedgerId(),
                Map.of("projectOid", projectOid, "oid", oid,"paymentChannelType", channelType, "level", PayAccountLevel.OrgChildren), 999999999L, -999999999L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建用户子账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }


    @SneakyThrows
    private PayAccount createOrgParentAccount(String projectOid, String oid) {
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setOid(oid);
        payAccount.setLevel(PayAccountLevel.OrgParent);
        String ledgerId = createLedger(new String[]{projectOid, oid}, "机构总账", null, Map.of("projectOid", projectOid, "oid", oid, "level", PayAccountLevel.OrgParent), 999999999L, -999999999L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建机构总账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }

    @SneakyThrows
    private PayAccount createUserChildrenAccount(String projectOid, String userId, PaymentChannelType channelType, PayAccount parent) {
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setParent(parent);
        payAccount.setUserId(userId);
        payAccount.setPaymentChannelType(channelType);
        payAccount.setLevel(PayAccountLevel.UserChildren);
        String ledgerId = createLedger(new String[]{projectOid, userId}, "用户子账-" + channelType.getRemark(), parent.getLedgerId(), Map.of("projectOid", projectOid, "paymentChannelType", channelType, "userId", userId) , 999999999L, 0L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建用户子账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }

    @SneakyThrows
    private PayAccount createUserParentAccount(String projectOid, String userId) {
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setUserId(userId);
        payAccount.setLevel(PayAccountLevel.UserParent);
        String ledgerId = createLedger(new String[]{projectOid, userId}, "用户总账", null, Map.of("projectOid", projectOid, "userId", userId), 999999999L, 0L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建用户总账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }


    @SneakyThrows
    private PayAccount createProjectChildrenAccount(String projectOid, PaymentChannelType channelType, PayAccount parent) {
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setParent(parent);
        payAccount.setPaymentChannelType(channelType);
        payAccount.setLevel(PayAccountLevel.projectChildren);
        String ledgerId = createLedger(new String[]{projectOid},"项目子账-" + channelType.getRemark(), parent.getLedgerId(), Map.of("projectOid", projectOid, "paymentChannelType", channelType), 99999999L, -99999999L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建项目子账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }


    @SneakyThrows
    private PayAccount createProjectParentAccount(String projectOid){
        PayAccount payAccount = new PayAccount();
        payAccount.setProjectOid(projectOid);
        payAccount.setLevel(PayAccountLevel.projectParent);
        String ledgerId = createLedger(new String[]{projectOid},"项目总账", null, Map.of("projectOid", projectOid), 99999999L, -99999999L);
        if (StringUtils.isBlank(ledgerId)){
            throw new Exception("支付中心创建项目总账失败");
        }
        payAccount.setLedgerId(ledgerId);
        payAccountDao.save(payAccount);
        return payAccount;
    }

    private String createLedger(String[] group, String name, String parentLedgerId, Map<String, Object> meta, long rangeMax, long rangeMin){
        GeneralLedgerTreeModel ledgerModel = new GeneralLedgerTreeModel();
        ledgerModel.setName(name);
        ledgerModel.setBalanceRangeMax(rangeMax);
        ledgerModel.setBalanceRangeMin(rangeMin);
        ledgerModel.setMeta(meta);

        if (StringUtils.isNotEmpty(parentLedgerId)){
            GeneralLedgerModel parentLedger = new GeneralLedgerModel();
            parentLedger.setId(parentLedgerId);
            ledgerModel.setParent(parentLedger);
        }

        com.github.microservice.pay.client.ret.ResultContent<GeneralLedgerTreeModel> generalLedgerTreeModelResultContent = generalLedgerService.create(ledgerModel);

        if (generalLedgerTreeModelResultContent.getState().equals(ResultState.Success)){
            return generalLedgerTreeModelResultContent.getContent().getId();
        }
        log.error("支付中心创建账户失败：{}", JsonUtil.toJson(generalLedgerTreeModelResultContent));
        return null;
    }

}
