package com.jeequan.jeepay.mgr.ctrl.cashout;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.paychannel.IRepayApiService;
import com.jeequan.jeepay.core.interfaces.paychannel.aliaqfbiz.IAliaqfApiService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.applyment.PaywayFee;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.df.Account;
import com.jeequan.jeepay.core.model.export.CashoutRecordExportExcel;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.mgr.ctrl.CommonCtrl;
import com.jeequan.jeepay.service.impl.*;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import lombok.AllArgsConstructor;
import lombok.Data;
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.web.bind.annotation.*;

import java.util.*;

/***
* 提现记录管理类
*
* @author terrfly
*
* @date 2022/3/23 16:45
*/
@RestController
@RequestMapping("/api/cashouts")
public class CashoutRecordController extends CommonCtrl {

    @Autowired private CashoutRecordService cashoutRecordService;
    @Autowired private MchAppService mchAppService;
    @Autowired private PayInterfaceConfigService payInterfaceConfigService;
    @Autowired private ConfigContextQueryService configContextQueryService;
    @Autowired private RateConfigService rateConfigService;
    @Autowired private OrderProfitSettRecordService orderProfitSettRecordService;
    @Autowired private MchInfoService mchInfoService;

    @PreAuthorize("hasAuthority('ENT_PROFIT_CASHOUT_RECORD_LIST')")
    @RequestMapping(value="", method = RequestMethod.GET)
    public ApiRes list() {
        CashoutRecord queryRecord = getObject(CashoutRecord.class);

        LambdaQueryWrapper<CashoutRecord> wrapper = CashoutRecord.gw();

        // 单号
        wrapper.eq(queryRecord.getRid() != null, CashoutRecord::getRid, queryRecord.getRid());

        // infoId
        wrapper.eq( StringUtils.isNotEmpty(queryRecord.getInfoId() ), CashoutRecord::getInfoId, queryRecord.getInfoId());

        // 状态查询
        wrapper.eq(queryRecord.getState() != null, CashoutRecord::getState, queryRecord.getState());

        // 名称搜索
        wrapper.like(StringUtils.isNotEmpty(queryRecord.getInfoName()), CashoutRecord::getInfoName, queryRecord.getInfoName());

        // 时间范围条件
        Date[] dateRange = queryRecord.buildQueryDateRange();
        if (dateRange[0] != null) {
            wrapper.ge(CashoutRecord::getCreatedAt, dateRange[0]);
        }
        if (dateRange[1] != null) {
            wrapper.le(CashoutRecord::getCreatedAt, dateRange[1]);
        }

        wrapper.orderByDesc(CashoutRecord::getCreatedAt);

        IPage<CashoutRecord> pages = cashoutRecordService.page(getIPage(), wrapper);
        return ApiRes.page(pages);
    }


    @PreAuthorize("hasAuthority('ENT_PROFIT_CASHOUT_RECORD_VIEW')")
    @RequestMapping(value="/{rid}", method = RequestMethod.GET)
    public ApiRes detail(@PathVariable("rid") Long rid) {
        return ApiRes.ok(cashoutRecordService.getById(rid));
    }


    /** 审核 **/
    @PreAuthorize("hasAuthority('ENT_PROFIT_CASHOUT_RECORD_AUDIT')")
    @RequestMapping(value="/audit/{rid}", method = RequestMethod.POST)
    public ApiRes audit(@PathVariable("rid") Long rid) {
        CashoutRecord record = getObject(CashoutRecord.class);
        cashoutRecordService.audit(rid, record.getState(), record.getAuditRemark(), record.getTransferCertImg());
        return ApiRes.ok();
    }

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

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

        return ApiRes.ok(result);
    }

    /**
     * @author: yr
     * @date: 2023/08/30 14:45
     * @describe: 服务商提现记录数据导出（佣金提现）
     */
    @RequestMapping(value="/exportExcel", method = RequestMethod.GET)
    public void exportExcel() {
        try {
            CashoutRecord cashoutRecord = getObject(CashoutRecord.class);
            JSONObject paramJSON = getReqParamJSON();
            LambdaQueryWrapper<CashoutRecord> wrapper = CashoutRecord.gw();

            IPage<CashoutRecord> pages = cashoutRecordService.listByPage(getIPage(true), cashoutRecord, paramJSON, wrapper);

            List<JSONObject> newList = new LinkedList<>();
            for (CashoutRecord cashout:pages.getRecords()) {
                JSONObject object = (JSONObject) JSONObject.toJSON(cashout);
                // 申请用户
                if (StringUtils.isNotEmpty(cashout.getInfoId())) {
                    object.put("infoName", cashout.getInfoName() + "(" + cashout.getInfoId() + ")");
                }
                object.put("settAccountType", cashout.getSettAccountType().replaceAll("_", ""));
                object.put("applyAmount", AmountUtil.convertCent2Dollar(cashout.getApplyAmount()));
                object.put("settAmount", AmountUtil.convertCent2Dollar(cashout.getSettAmount()));
                object.put("settFeeAmount", AmountUtil.convertCent2Dollar(cashout.getSettFeeAmount()));
                newList.add(object);
            }

            List<CashoutRecordExportExcel> linkedList = JSONArray.parseArray(JSONArray.toJSONString(newList), CashoutRecordExportExcel.class);
            // excel输出
            ExcelUtil.exportExcel(linkedList, "提现记录", "提现记录", CashoutRecordExportExcel.class, "提现记录", response);
        }catch (Exception e) {
            logger.error("导出excel失败", e);
            throw new BizException("导出订单失败！");
        }
    }

    /** 提现选择 灵活用工渠道时， 查询当前配置的自营商户的应用信息 **/
//    @PreAuthorize("hasAuthority('ENT_PROFIT_CASHOUT_RECORD_AUDIT')")
    @GetMapping("/platformSelfMchNoAppInfos")
    public ApiRes platformSelfMchNoAppInfos() {

        // 当前结算信息
        CashoutRecord cashoutRecord = cashoutRecordService.getById(getValLongRequired("rid"));

        // 订单不存在
        if(cashoutRecord == null || cashoutRecord.getState() != CashoutRecord.CASHOUT_STATE_AUDIT_ING){
            throw new BizException("审核订单不存在");
        }

        // 自营商户号
        String platformSelfMchNo = sysConfigService.getDBDefaultConfig().getPlatformSelfMchNo();
        if(StringUtils.isEmpty(platformSelfMchNo)){
            throw new BizException("自营商户未配置， 请前往系统管理进行配置");
        }

        MchInfo mchInfo = mchInfoService.getById(platformSelfMchNo);
        if(mchInfo == null || mchInfo.getState() != CS.YES){
            throw new BizException("自营商户不存在或状态不可用");
        }

        // 查询全部应用信息
        List<MchAppEntity> mchAppList = mchAppService.list(MchAppEntity.gw()
                .select(MchAppEntity::getAppId, MchAppEntity::getAppName)
                .eq(MchAppEntity::getMchNo, platformSelfMchNo).eq(MchAppEntity::getState, CS.YES));

        for (MchAppEntity mchApp : mchAppList) {
            mchApp.addExt("transIfCodeInfoList", this.packageTransIfCodeItem(cashoutRecord, cashoutRecord.getSettAccountType(), platformSelfMchNo, mchInfo.getType(),mchApp));
        }
        return ApiRes.ok(mchAppList);
    }

    // 封装 应用对应的转账渠道列表
    private List<InnerTransIfCode> packageTransIfCodeItem(CashoutRecord cashoutRecord, String settAccountType, String mchNo, Byte mchType, MchAppEntity mchApp){

        // 支付接口列表
        List<InnerTransIfCode> result = new ArrayList<>();

        // 微信转账（仅支持普通商户）  查询是否开通了对应渠道
        if( TransferOrderEntity.ENTRY_WX_CASH.equals(settAccountType) && mchType == MchInfo.TYPE_NORMAL){

            // 是否已正确配置
            if(payInterfaceConfigService.mchAppHasAvailableIfCode(mchApp.getAppId(), CS.IF_CODE.WXPAY)){
                result.add(new InnerTransIfCode(CS.IF_CODE.WXPAY, "微信支付", null, null, null));
            }

        }

        // 支付宝转账（仅支持普通商户）  查询是否开通了对应渠道
        if( TransferOrderEntity.ENTRY_ALIPAY_CASH.equals(settAccountType) && mchType == com.jeequan.jeepay.db.entity.MchInfo.TYPE_NORMAL){

            // 是否已正确配置
            if(payInterfaceConfigService.mchAppHasAvailableIfCode(mchApp.getAppId(), CS.IF_CODE.ALIPAY)){
                result.add(new InnerTransIfCode(CS.IF_CODE.ALIPAY, "支付宝", null, null, null));
            }

        }

        // 支付宝安全发转账产品（仅支持特约商户）  查询是否开通了对应渠道
        if( TransferOrderEntity.ENTRY_ALIPAY_CASH.equals(settAccountType) && mchType == MchInfo.TYPE_ISVSUB){

            // 是否已正确配置
            if(payInterfaceConfigService.mchAppHasAvailableIfCode(mchApp.getAppId(), CS.IF_CODE.ALIAQF)){

                try { // 查询余额

                    IAliaqfApiService aliaqfApiService = SpringBeansUtil.getBean(CS.IF_CODE.ALIAQF + "ApiService", IAliaqfApiService.class);
                    MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(mchNo, mchApp.getAppId(),null);
                    JSONObject accountBookInfo = aliaqfApiService.fundAccountbookQuery(mchAppConfigContext);
                    result.add(new InnerTransIfCode(CS.IF_CODE.ALIAQF, "支付宝安全发",
                            AmountUtil.convertDollar2CentLong(accountBookInfo.getString("available_amount"))
                            , null
                            , null
                    ));

                } catch (BizException e) {
                    // 查询接口异常， 不影响页面显示。
                    result.add(new InnerTransIfCode(CS.IF_CODE.ALIAQF, "支付宝安全发", null, null, null));
                    logger.error("查询支付宝安全发余额异常！", e);
                }
            }
            //如果打款配置为空
            if(result.isEmpty()){
                IRepayApiService repayApiService = SpringBeansUtil.getBean(CS.IF_CODE.FLPAY + "RepayApiService", IRepayApiService.class);
                if(repayApiService != null){
                    Account account = repayApiService.queryAccountBalance(mchNo, AccountInfo.Type.REFUND.getType());
                    result.add(new InnerTransIfCode(CS.IF_CODE.FLPAY, "福穗·灵工",
                            account.getBalance(), null, 1L
                    ));
                }
            }
        }

        // 计算手续费
        for (InnerTransIfCode innerTransIfCode : result) {
            innerTransIfCode.setTransferPlatformMchfeeAmount(calTransferPlatformMchfeeAmount(cashoutRecord, innerTransIfCode.ifCode, mchNo, mchType, mchApp));
            innerTransIfCode.setTransferPlatformCostAmount(calTransferPlatformCostAmount(cashoutRecord, innerTransIfCode.ifCode, mchNo, mchType, mchApp));
        }

        return result;
    }

    /** 计算： 结算手续费（ 仅商户费率费用 ） **/
    private Long calTransferPlatformMchfeeAmount(CashoutRecord cashoutRecord, String ifCode, String mchNo, Byte mchType, MchAppEntity mchApp){

        try {
            // 转账手续费，  可以为空。
            PaywayFee paywayFee = rateConfigService.queryTransferCreateOrderPaywayFee(mchNo,null, mchApp.getAppId(), ifCode, CS.PAY_WAY_CODE.TRANSFER);

            if(paywayFee != null){
                MutablePair<String, Long> feeAndSnapshot = paywayFee.calFeeAndSnapshot(cashoutRecord.getSettAmount());
                return feeAndSnapshot.right;
            }
            return null;

        } catch (Exception e) {
            logger.error("计算手续费异常", e);
            return null;
        }
    }

    private Long calTransferPlatformCostAmount(CashoutRecord cashoutRecord, String ifCode, String mchNo, Byte mchType, MchAppEntity mchApp){

        // 商户 费率费用
        Long transferPlatformMchfeeAmount = calTransferPlatformMchfeeAmount(cashoutRecord, ifCode, mchNo, mchType, mchApp);

        try {

            if(transferPlatformMchfeeAmount == null){
                return null;
            }

            // 普通商户， 计算商户的费率费用
            if(mchType == com.jeequan.jeepay.db.entity.MchInfo.TYPE_NORMAL){
                return transferPlatformMchfeeAmount;
            }

            // 以下为特约商户  ( 参考 转账成功 插入 分润表逻辑 )
            MchInfo mchInfo = mchInfoService.getById(mchNo);

            // 商户配置费率
            PaywayFee paywayFeeByMch = rateConfigService.getPaywayFeeByMch(ifCode, CS.PAY_WAY_CODE.TRANSFER,null,mchApp.getRange(),mchApp.getMccCode(),mchInfo.getIsvNo());

            // 平台底价
            PaywayFee paywayFeeByIsv = rateConfigService.getPaywayFeeByIsvCost(ifCode, CS.PAY_WAY_CODE.TRANSFER, mchInfo.getIsvNo(),mchApp.getRange(),mchApp.getMccCode());

            // 代理商的底价
            List<MutablePair<String, PaywayFee>> paywayFeeByAgentList = new ArrayList<>();

            // 商户的所属代理商
            if(StringUtils.isNotEmpty(mchInfo.getAgentNo())) {
                // 全部的代理商号  三级 --》 二级 --》 顶级
                List<String> allAgentNo = agentInfoService.queryAllParentAgentNo(mchInfo.getAgentNo());
                Collections.reverse(allAgentNo);

                for (String agentNo : allAgentNo) {
                    PaywayFee paywayFeeByAgent = rateConfigService.getPaywayFeeByAgent(ifCode, CS.PAY_WAY_CODE.TRANSFER, agentNo,mchApp.getRange(),mchApp.getMccCode(),mchInfo.getIsvNo());
                    paywayFeeByAgentList.add(MutablePair.of(agentNo, paywayFeeByAgent));
                }
            }

            // 计算佣金
            List<OrderProfitSettRecord> result = orderProfitSettRecordService.calAllRoleProfit(mchNo, cashoutRecord.getSettAmount(), paywayFeeByMch, paywayFeeByIsv, paywayFeeByAgentList,OrderProfitSettRecord.CAL_TYPE_TRANS_ORDER,cashoutRecord.getTransferOrderId());
            orderProfitSettRecordService.recordListOrderByInfo(result); // 排序


            for (OrderProfitSettRecord orderProfitSettRecord : result) {

                // 得到平台利润
                if(CS.INFO_ID_ENUM.PLATFORM_PROFIT.equals(orderProfitSettRecord.getInfoId()) && CS.SYS_ROLE_TYPE.PLATFORM.equals(orderProfitSettRecord.getInfoType())){
                    return AmountUtil.minZero(transferPlatformMchfeeAmount - orderProfitSettRecord.getCalProfitAmount());
                }
            }

            return transferPlatformMchfeeAmount;
        } catch (Exception e) {
            logger.error("计算手续费异常：", e);
            return transferPlatformMchfeeAmount;
        }
    }

    @Data
    @AllArgsConstructor
    private static class InnerTransIfCode{

        private String ifCode;
        private String ifCodeName;
        private Long balance;

        /** 商户手续费 **/
        private Long transferPlatformMchfeeAmount;

        /** 实际成本 **/
        private Long transferPlatformCostAmount;

    }
}
