package org.dromara.payment.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.enums.BusRole;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.payment.bill.domain.MerBillDetail;
import org.dromara.payment.bill.service.IMerBillService;
import org.dromara.payment.channel.service.IBusChannelCashoutService;
import org.dromara.payment.merchant.domain.BusMerchantAccount;
import org.dromara.payment.merchant.mapper.BusMerchantAccountMapper;
import org.dromara.payment.merchant.service.IBusMerchantCashoutService;
import org.dromara.payment.operator.domain.BusOperatorAccount;
import org.dromara.payment.operator.mapper.BusOperatorAccountMapper;
import org.dromara.payment.operator.service.IBusOperatorCashoutService;
import org.dromara.payment.sys.domain.SysSydAccount;
import org.dromara.payment.sys.mapper.SysSydAccountMapper;
import org.dromara.payment.sys.service.ISysSydCashoutService;
import org.dromara.settlement.api.RemoteAccountService;
import org.dromara.settlement.api.domain.Result;
import org.dromara.settlement.api.domain.TransactionLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.payment.common.domain.bo.TranLogBo;
import org.dromara.payment.common.domain.vo.TranLogVo;
import org.dromara.payment.common.domain.TranLog;
import org.dromara.payment.common.mapper.TranLogMapper;
import org.dromara.payment.common.service.ITranLogService;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 交易记录Service业务层处理
 *
 * @author LionLi
 * @date 2024-04-11
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class TranLogServiceImpl implements ITranLogService {

    private final TranLogMapper baseMapper;

    private final SysSydAccountMapper sydAccountDao;

    private final BusOperatorAccountMapper  busOperatorAccountMapper;

    private final BusMerchantAccountMapper accountDao;

    private final IMerBillService billService;

    private final ISysSydCashoutService sydCashoutService;

    private final IBusMerchantCashoutService merchantCashoutService;

    private final IBusChannelCashoutService channelCashoutService;

    private final IBusOperatorCashoutService operatorCashoutService;

    @DubboReference
    private RemoteAccountService accountService;

    /**
     * 查询交易记录
     */
    @Override
    public TranLogVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询交易记录列表
     */
    @Override
    public TableDataInfo<TranLogVo> queryPageList(TranLogBo bo, PageQuery pageQuery) {
        QueryWrapper<TranLog> lqw = buildQueryWrapper(bo);
        Page<TranLogVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询交易记录列表
     */
    @Override
    public List<TranLogVo> queryList(TranLogBo bo) {
        QueryWrapper<TranLog> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private QueryWrapper<TranLog> buildQueryWrapper(TranLogBo bo) {
        Map<String, Object> params = bo.getParams();
        QueryWrapper<TranLog> lqw = new QueryWrapper<>();
        lqw.eq(bo.getBusType() != null, "bus_type", bo.getBusType());
        lqw.eq(bo.getBusItem() != null, "bus_item", bo.getBusItem());
        lqw.eq(bo.getBuisId() != null, "buis_id", bo.getBuisId());
        lqw.eq(StringUtils.isNotBlank(bo.getBusBatch()), "bus_batch", bo.getBusBatch());
        lqw.eq(bo.getTranId() != null, "tran_id", bo.getTranId());
        lqw.eq(bo.getAddTime() != null, "add_time", bo.getAddTime());
        lqw.eq(bo.getTranResult() != null, "tran_result", bo.getTranResult());
        lqw.eq(StringUtils.isNotBlank(bo.getTranBatch()), "tran_batch", bo.getTranBatch());
        lqw.eq(bo.getTranTime() != null, "tran_time", bo.getTranTime());
        lqw.eq(bo.getSourceAccId() != null, "source_acc_id", bo.getSourceAccId());
        lqw.eq(bo.getSourceAccType() != null, "source_acc_type", bo.getSourceAccType());
        lqw.eq(bo.getTargetAccId() != null, "target_acc_id", bo.getTargetAccId());
        lqw.eq(bo.getTargetAccType() != null, "target_acc_type", bo.getTargetAccType());
        lqw.eq(StringUtils.isNotBlank(bo.getBankNo()), "bank_no", bo.getBankNo());
        lqw.eq(bo.getIsCallback() != null, "is_callback", bo.getIsCallback());
        return lqw;
    }

    /**
     * 新增交易记录
     */
    @Override
    public Boolean insertByBo(TranLogBo bo) {
        TranLog add = MapstructUtils.convert(bo, TranLog.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改交易记录
     */
    @Override
    public Boolean updateByBo(TranLogBo bo) {
        TranLog update = MapstructUtils.convert(bo, TranLog.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TranLog entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除交易记录
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean synTransferCallBack(TranLogVo tlog) {
        Result<String> rtn = accountService.getTransferBankNo(tlog.getTranId());
        if (rtn.hasError()) {
            throw new ServiceException("同步银行交易流水号出错："+rtn.getResult());
        }else if (rtn.hasTip()) {
            throw new ServiceException("同步银行交易流水号："+rtn.getResult());
        }else if (StringUtils.isNotBlank(rtn.getRtnData())) {
            tlog.setBankNo(rtn.getRtnData());
            rtn = accountService.getTransferCallBack(tlog.getTranId());
            if (rtn.hasError()) {
                throw new ServiceException("同步银行交易回置单出错："+rtn.getResult());
            }else if (rtn.hasTip()) {
                throw new ServiceException("同步银行交易回置单结果："+rtn.getResult());
            }else if (StringUtils.isNotBlank(rtn.getRtnData())) {
                if (tlog.getBusType() == 2) {//账单
                    billService.billTransactionCallback(tlog,rtn.getRtnData());
                }
                if (StringUtils.isNotBlank(tlog.getBankNo())) {
                    TranLog upd = new TranLog();
                    upd.setId(tlog.getId());
                    upd.setBankNo(tlog.getBankNo());
                    upd.setIsCallback(1);
                    baseMapper.updateById(upd);
                }
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean transaction(TranLogVo accid,boolean syn) {
        boolean lock = false;
        if(accid.getSourceAccType() == BusRole.SERVICE.getId()){
            lock = sydAccountDao.lock(accid.getSourceAccId().intValue()) > 0;
        }else if (accid.getSourceAccType() == BusRole.MERCHANT.getId()){
            lock = accountDao.lock(accid.getSourceAccId().intValue()) > 0;
        }else if(accid.getSourceAccType() == BusRole.OPERATOR.getId()){
            lock = this.busOperatorAccountMapper.lock(accid.getSourceAccId().intValue()) > 0;
        }

        if(lock) {
            Result<TransactionLog> rtn = null;
            if (syn){
                rtn = accountService.synTransfer(accid.getTranId());
                log.info("查询交易返回结果==>"+accid.getTranId()+","+JsonUtils.toJsonString(rtn));
                if (rtn.hasError()) {
                    throw new ServiceException("同步银行交易结果出错（" + JsonUtils.toJsonString(accid) + "）：" + rtn.getResult());
                } else if (rtn.hasTip()) {
                    throw new ServiceException("同步银行交易结果提示（" + JsonUtils.toJsonString(accid) + "）：" + rtn.getResult());
                }
                if(rtn.getRtnData().getResult() == -1) {
                    //需要重新发起支付
                    rtn.getRtnData().setResult((short)4);
                }
            }else {
                rtn = accountService.transfer(accid.getTranId());
                log.info("交易返回结果==>"+accid.getTranId()+","+JsonUtils.toJsonString(rtn));
                if (rtn.hasError()) {
                    throw new ServiceException("银行交易出错（" + JsonUtils.toJsonString(accid) + "）：" + rtn.getResult());
                } else if (rtn.hasTip()) {
                    throw new ServiceException("银行交易提示（" + JsonUtils.toJsonString(accid) + "）：" + rtn.getResult());
                }
            }
            if (rtn.getRtnData() != null && rtn.getRtnData().getResult() > 0) {
                TranLog save = null;
                if(rtn.getRtnData().getResult() == 4) {//重新发起支付
                    save = new TranLog(accid.getId(),-1);
                }else if (rtn.getRtnData().getResult() == 1) {//支付中
                    if(accid.getTranResult() < 1) {
                        save = new TranLog(accid.getId(), 1);
                    }
                }else {
                    if (accid.getBusType() == 2) {//账单
                        save = billService.billTransaction(accid, rtn.getRtnData());
                    }else if (accid.getBusType() == 5) {//服务商提现
                        save = sydCashoutService.cashoutResult(accid, rtn.getRtnData());
                    }else if (accid.getBusType() == 6) {//商户提现
                        save = merchantCashoutService.cashoutResult(accid, rtn.getRtnData());
                    }else if (accid.getBusType() == 3) {//代理商提现
                        save = channelCashoutService.cashoutResult(accid, rtn.getRtnData());
                    }else if (accid.getBusType() == 4) {//运营商提现
                        save = operatorCashoutService.cashoutResult(accid, rtn.getRtnData());
                    }
                }
                if (save != null) {
                    save.setBankNo(rtn.getRtnData().getTargetBankNo());
                    baseMapper.updateById(save);
                }
            }
            unlockTransaction(accid);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unlockTransaction(TranLogVo accid) {
        if(accid.getSourceAccType() == BusRole.SERVICE.getId()){
            sydAccountDao.update(new LambdaUpdateWrapper<SysSydAccount>().eq(SysSydAccount::getAccId,accid.getSourceAccId())
                .set(SysSydAccount::getStatus,1));
        }else if (accid.getSourceAccType() == BusRole.MERCHANT.getId()){
            accountDao.update(new LambdaUpdateWrapper<BusMerchantAccount>().eq(BusMerchantAccount::getAccId,accid.getSourceAccId())
                .set(BusMerchantAccount::getStatus,1));
        }else if(accid.getSourceAccType() == BusRole.OPERATOR.getId()){
            busOperatorAccountMapper.update(new LambdaUpdateWrapper<BusOperatorAccount>().eq(BusOperatorAccount::getAccId,accid.getSourceAccId())
                .set(BusOperatorAccount::getStatus,1));
        }
        return true;
    }
}
