package com.liquidnet.service.reconciliation.biz;

import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.reconciliation.constant.ReconConstants.BankChannelEnum;
import com.liquidnet.service.reconciliation.constant.ReconConstants.BatchStatusEnum;
import com.liquidnet.service.reconciliation.constant.ReconConstants.LockTypeEnum;
import com.liquidnet.service.reconciliation.constant.ReconConstants;
import com.liquidnet.service.reconciliation.entity.LrAccountCheckBatch;
import com.liquidnet.service.reconciliation.service.ILrAccountCheckBatchService;
import com.liquidnet.service.reconciliation.service.core.BuildNoService;
import com.liquidnet.service.reconciliation.strategy.accounting.ComparingAccountStrategyContext;
import com.liquidnet.service.reconciliation.strategy.funddata.GetFundDataStrategyContext;
import com.liquidnet.service.reconciliation.strategy.funddata.IGetFundDataStrategy;
import com.liquidnet.service.reconciliation.util.FundFlowUtil;
import com.liquidnet.service.reconciliation.vo.ReconciliationEntityVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author AnJiabin <jiabin.an@lightnet.io>
 * @version V1.0
 * @Description:
 * @class: ReconciliationMainBiz
 * @Package com.liquidnet.service.reconciliation.biz
 * @Copyright: LightNet @ Copyright (c) 2020
 * @date 2020/12/8 5:28 下午
 */
@Component("reconciliationMainBiz")
public class ReconciliationMainBiz {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
    @Autowired
    private ReconciliationFileDownBiz fileDownBiz;
    @Autowired
    private ReconciliationFileParserBiz parserBiz;
    @Autowired
    private ReconciliationValidateBiz validateBiz;
    @Autowired
    private ILrAccountCheckBatchService batchService;
    @Autowired
    private BuildNoService buildNoService;

    @Autowired
    private ComparingAccountStrategyContext comparingAccountStrategyContext;

    @Autowired
    private GetFundDataStrategyContext getFundDataStrategyContext;

    public void accountingMain(String bankChannel,Date beginDate, Date endDate) {
        if(StringUtil.isEmpty(bankChannel)){
            log.error("accountingMain bankChannel:{} is null",bankChannel);
            return;
        }
        if(!BankChannelEnum.toList().contains(bankChannel)){
            log.error("accountingMain bankChannel:{} is not exist",bankChannel);
            return;
        }

        //资金流数据是否来自对账文件（否则来自本地查询）
        boolean dataIsFromFile = false;
        List<ReconciliationEntityVo> bankDataList = null;
        //
        LrAccountCheckBatch batch = new LrAccountCheckBatch();
        // 获取需要对账的对账单时间
        Date billDate = beginDate;

        try {
            if (FundFlowUtil.lockUtils(bankChannel, LockTypeEnum.UPLOAD_LOCK.getCode())) {
                /** step1:判断是否对过账 **/
                if (this.stepValidate(batch, bankChannel, billDate)) {
                    if (dataIsFromFile) {
                        /** step2:对账文件下载 **/
                        /** step3:解析对账文件 **/
                        bankDataList = this.stepDownloadAndParserData(batch, bankChannel, billDate);
                    } else {
                        /** 对账数据通过本地查询获取*/
                        bankDataList = getFundDataStrategyContext.getStrategy(bankChannel).getTransFundData(batch, bankChannel, billDate);
                    }
                } else {
                    return;
                }
            } else {
                return;
            }

        } catch (Exception e) {
            log.error("roncoo-app-reconciliation error:", e);
        } finally {
            FundFlowUtil.releaseLock(bankChannel,LockTypeEnum.UPLOAD_LOCK.getCode());
        }

        //判断
        if (StringUtil.isNull(bankDataList)||bankDataList.size()==0) {
            log.info("accountingMain bankChannel:{} bankDataListSize:{} ",bankChannel,bankDataList.size());
            return;
        }

        try{
            if(FundFlowUtil.lockUtils(bankChannel,LockTypeEnum.ACCOUNTING_LOCK.getCode())){
                /** step4:对账流程 **/
                this.stepCheck(bankDataList,batch,bankChannel,billDate);
                /** step5:清理缓冲池 **/
                this.stepCleanChache(batch,bankChannel,billDate);
            }else{
                return;
            }

        } catch (Exception e) {
            log.error("roncoo-app-reconciliation error:", e);
        } finally {
            FundFlowUtil.releaseLock(bankChannel,LockTypeEnum.ACCOUNTING_LOCK.getCode());
        }

    }

    private boolean stepValidate(LrAccountCheckBatch batch,String bankChannel,Date billDate){
        /** step1:判断是否对过账 **/
        Boolean checked = validateBiz.isChecked(bankChannel, billDate);
        if (checked) {
            log.info("账单日[" + sdf.format(billDate) + "],支付方式[" + bankChannel + "],已经对过账，不能再次发起自动对账。");
            return false;
        }

        // 创建对账批次
        batch.setCreater("reconciliationSystem");
        batch.setCreateTime(new Date());
        batch.setBillDate(billDate);
        batch.setBatchNo(buildNoService.buildReconciliationNo(bankChannel));
        batch.setBankType(bankChannel);
        return true;
    }
    private List<ReconciliationEntityVo> stepDownloadAndParserData(LrAccountCheckBatch batch,String bankChannel,Date billDate){
        /** step2:对账文件下载 **/
        File file = null;
        try {
            log.info("ReconciliationFileDownBiz,对账文件下载开始");
            file = fileDownBiz.downReconciliationFile(bankChannel, billDate);
            if (file == null) {
            }
            log.info("对账文件下载结束");
        } catch (Exception e) {
            log.error("对账文件下载异常:", e);
            batch.setStatus(BatchStatusEnum.FAIL.name());
            batch.setRemark("对账文件下载异常");
            batchService.save(batch);
        }

        /** step3:解析对账文件 **/
        List<ReconciliationEntityVo> bankList = null;
        try {
            log.info("=ReconciliationFileParserBiz=>对账文件解析开始>>>");

            // 解析文件
            bankList = parserBiz.parser(batch, file, billDate, bankChannel);
            // 如果下载文件异常，退出
            if (BatchStatusEnum.ERROR.name().equals(batch.getStatus())) {

            }
            log.info("对账文件解析结束");
        } catch (Exception e) {
            log.error("对账文件解析异常:", e);
            batch.setStatus(BatchStatusEnum.FAIL.name());
            batch.setRemark("对账文件解析异常");
            batchService.save(batch);
        }

        return bankList;
    }

    private void stepCheck(List<ReconciliationEntityVo> bankList,LrAccountCheckBatch batch,String bankChannel,Date billDate){
        /** step4:对账流程 **/
        try {
            comparingAccountStrategyContext.getStrategy(bankChannel).check(bankList, batch);
        } catch (Exception e) {
            log.error("对账异常:", e);
            batch.setStatus(BatchStatusEnum.FAIL.name());
            batch.setRemark("对账异常");
            batchService.save(batch);
        }
    }
    private void stepCleanChache(LrAccountCheckBatch batch,String bankChannel,Date billDate){
        /** step5:清理缓冲池 **/
        // 如果缓冲池中有三天前的数据就清理掉并记录差错
        validateBiz.validateScratchPool();
    }
}
