package com.jeequan.jeepay.agent.ctrl.account;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.agent.ctrl.CommonCtrl;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.applyment.CashoutFee;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.db.entity.AgentInfo;
import com.jeequan.jeepay.db.entity.CashoutRecord;
import com.jeequan.jeepay.db.entity.InfoAccount;
import com.jeequan.jeepay.service.impl.AgentInfoService;
import com.jeequan.jeepay.service.impl.CashoutRecordService;
import com.jeequan.jeepay.service.impl.InfoAccountService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * 提现结算记录表
 *
 * @author xiaoyu
 * @date 2022/3/21 10:00
 */
@RestController
@RequestMapping("/api/cashout")
public class CashoutRecordController extends CommonCtrl {

    @Autowired private CashoutRecordService cashoutRecordService;
    @Autowired private AgentInfoService agentInfoService;
    @Autowired private SysConfigService sysConfigService;
    @Autowired private InfoAccountService infoAccountService;

    /**
     * @author: xiaoyu
     * @date: 2022/3/21 10:01
     * @describe: 提现记录
     */
    @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_LIST')")
    @GetMapping
    public ApiRes list() {

        CashoutRecord record = getObject(CashoutRecord.class);
        JSONObject paramJSON = getReqParamJSON();
        record.setInfoId(getCurrentAgentNo());
        record.setInfoType(CS.SYS_ROLE_TYPE.AGENT);
        LambdaQueryWrapper<CashoutRecord> wrapper = CashoutRecord.gw();
        IPage<CashoutRecord> pages = cashoutRecordService.listByPage(getIPage(), record, paramJSON, wrapper);
        pages.getRecords().stream().forEach(i -> {
            i.setSettAccountName(DesensitizedUtil.chineseName(i.getSettAccountName()));
            i.setSettAccountTelphone(DesensitizedUtil.mobilePhone(i.getSettAccountTelphone()));
            i.setSettAccountNo(DesensitizedUtil.bankCard(i.getSettAccountNo()));

            // 平台手续费不对服务商显示
            i.setTransferPlatformCostAmount(null); i.setTransferPlatformMchfeeAmount(null);
            i.setTransferMchAppId(null);
            i.setTransferIfCode(null);
            i.setTransferOrderId(null);
        });

        return ApiRes.page(pages);
    }

    /**
     * @author: xiaoyu
     * @date: 2022/3/21 10:21
     * @describe: 提现结算记录详情
     */
    @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_DETAIL')")
    @GetMapping("/{rid}")
    public ApiRes detail(@PathVariable("rid") String rid) {
        Byte originData = getValByteDefault("originData", CS.YES);

        CashoutRecord record = cashoutRecordService.getById(rid);
        if (CS.NO == originData) {
            // 数据脱敏
            record.setSettAccountName(DesensitizedUtil.chineseName(record.getSettAccountName()));
            record.setSettAccountTelphone(DesensitizedUtil.mobilePhone(record.getSettAccountTelphone()));
            record.setSettAccountNo(DesensitizedUtil.bankCard(record.getSettAccountNo()));
        }

        if (record == null) {
            return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
        }
        if (!record.getInfoId().equals(getCurrentAgentNo())) {
            return ApiRes.fail(ApiCodeEnum.SYS_PERMISSION_ERROR);
        }

        // 钱包余额
        InfoAccount infoAccount = infoAccountService.queryById(getCurrentAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
        record.addExt("realBalanceAmount", infoAccount == null ? 0L : infoAccount.getBalanceAmount());
        record.addExt("unAmount", infoAccount == null ? 0L : infoAccount.getUnAmount());
        record.addExt("auditProfitAmount", infoAccount == null ? 0L : infoAccount.getAuditProfitAmount());
        // 页面上的钱包余额
        Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount();
        record.addExt("availableBalanceAmount", availableBalanceAmount);
        AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());
        // 冻结金额 及 冻结原因
        Long freezeAmount = agentInfo == null ? 0L : agentInfo.getFreezeAmount();
        record.addExt("freezeAmount", freezeAmount);
        record.addExt("freezeDesc", agentInfo == null ? "" : agentInfo.getFreezeDesc());
        // 可提现金额（页面上的钱包余额-冻结金额）
        record.addExt("allowTakeAmount", Math.max(availableBalanceAmount - freezeAmount, 0L));

        // 平台手续费不对服务商显示
        record.setTransferPlatformCostAmount(null); record.setTransferPlatformMchfeeAmount(null);
        record.setTransferMchAppId(null);
        record.setTransferIfCode(null);
        record.setTransferOrderId(null);

        return ApiRes.ok(record);
    }

    /**
     * @author: xiaoyu
     * @date: 2022/3/21 10:21
     * @describe: 发起提现
     */
    @MethodLog( remark = "佣金提现")
    @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_SETT')")
    @PostMapping("/sett")
    public ApiRes sett() {

        String sipw = Base64.decodeStr(getValStringRequired("sipw"));

        // 查询当前服务商结算信息
        AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());

        if(StringUtils.isEmpty(agentInfo.getSipw())){
            throw new BizException("当前未设置支付密码，请进入[账号中心-系统配置-安全管理]设置支付密码");
        }

        if(!new BCryptPasswordEncoder().matches(sipw, agentInfo.getSipw())){
            throw new BizException("支付密码验证失败！");
        }

        // 结算参数
        AgentInfo infoParams = getObject(AgentInfo.class);
        if (infoParams == null) {
            return ApiRes.fail(ApiCodeEnum.SYS_OPERATION_FAIL_SEARCH);
        }
        if (StringUtils.isEmpty(agentInfo.getSettAccountType()) || StringUtils.isEmpty(agentInfo.getSettAccountNo())) {
            throw new BizException("请先联系平台配置结算账户信息");
        }
        if (StringUtils.isEmpty(infoParams.getContactTel()) || StringUtils.isEmpty(infoParams.getContactName())) {
            throw new BizException("结算用户名/联系人手机号不可为空");
        }

        // 提现金额 元转分
        Long applyAmount = Long.valueOf(AmountUtil.convertDollar2Cent(getValStringRequired("amount")));

        // 提现金额小于最大可提现金额才允许发起提现
        InfoAccount infoAccount = infoAccountService.queryById(agentInfo.getAgentNo(), CS.SYS_ROLE_TYPE.AGENT);
        // 页面上的钱包余额
        Long availableBalanceAmount = infoAccount == null ? 0L : infoAccount.getBalanceAmount() - infoAccount.getUnAmount();
        // 可提现金额（页面上的钱包余额-冻结金额）单位：分
        if (applyAmount > Math.max(availableBalanceAmount - agentInfo.getFreezeAmount(), 0L)) {
            throw new BizException("提现金额超限，请刷新页面后重试");
        }

        CashoutRecord record = getObject(CashoutRecord.class);
        record.setApplyAmount(applyAmount);

        record.setState(CashoutRecord.CASHOUT_STATE_AUDIT_ING); // 待审核
        record.setInfoId(getCurrentAgentNo());
        record.setInfoType(CS.SYS_ROLE_TYPE.AGENT);
        record.setInfoName(agentInfo.getAgentShortName());
        record.setSettType(CashoutRecord.SETT_TYPE_COMM);

        CashoutFee cashoutFee = null;
        // 使用默认
        if(agentInfo.getCashoutFeeRuleType() == 1){
            cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class);
        }else{
            cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class);
        }

        if(cashoutFee.getApplyLimit() != null && record.getApplyAmount() < cashoutFee.getApplyLimit() ){
            throw new BizException("提现额度不可小于" + AmountUtil.convertCent2Dollar(cashoutFee.getApplyLimit()) + "元");
        }

        MutablePair<String, Long> feePair = cashoutFee.calFeeAndSnapshot(record.getApplyAmount());

        record.setSettFeeRule(feePair.left);
        record.setSettFeeAmount(feePair.right);
        record.setSettAmount(record.getApplyAmount() - record.getSettFeeAmount());

        if(record.getApplyAmount() <= 0 || record.getSettFeeAmount() < 0 || record.getSettAmount() <= 0){
            throw new BizException(String.format("提现金额计算错误！ 申请: %s元， 手续费%s元， 到账:%s元",
                    AmountUtil.convertCent2Dollar(record.getApplyAmount()),
                    AmountUtil.convertCent2Dollar(record.getSettFeeAmount()),
                    AmountUtil.convertCent2Dollar(record.getSettAmount())
                    ));
        }

        // 结算账户信息
        record.setSettAccountType(agentInfo.getSettAccountType());

        // 结算人姓名： 优先取值运营平台设置的费率， 如果为空，那么取 服务商申请时填入的。
        record.setSettAccountName(StringUtils.defaultIfEmpty(infoParams.getSettAccountName(), record.getContactName()));
        record.setContactName(infoParams.getContactName());
        record.setSettAccountBank(agentInfo.getSettAccountBank());
        record.setSettAccountSubBank(agentInfo.getSettAccountSubBank());
        record.setSettAccountNo(agentInfo.getSettAccountNo());
        record.setSettAccountTelphone(infoParams.getContactTel());

        // 发起提现
        cashoutRecordService.settAmount(record);

        return ApiRes.ok();
    }

    /**
     * @author: xiaoyu
     * @date: 2022/3/29 16:54
     * @describe: 获取当前服务商费率
     */
    @PreAuthorize("hasAuthority('ENT_CASHOUT_PAYWAY_FEE')")
    @GetMapping("/paywayFee")
    public ApiRes getPaywayFee() {
        AgentInfo agentInfo = agentInfoService.getById(getCurrentAgentNo());

        CashoutFee cashoutFee = null;
        // 使用默认
        if(agentInfo.getCashoutFeeRuleType() == 1){
            cashoutFee = JSON.parseObject(sysConfigService.getById("castOutFeeRule").getConfigVal(), CashoutFee.class);
        }else{
            cashoutFee = JSON.parseObject(agentInfo.getCashoutFeeRule(), CashoutFee.class);
        }

        return ApiRes.ok(cashoutFee);
    }

    /** 统计 **/
    @PreAuthorize("hasAuthority('ENT_CASHOUT_RECORD_COUNT')")
    @GetMapping(value="/count")
    public ApiRes count() {

        CashoutRecord record = getObject(CashoutRecord.class);
        record.setInfoId(getCurrentAgentNo());
        Map<String, Object> result = cashoutRecordService.countByCashout(record);

        return ApiRes.ok(result);
    }
}
