package com.jeequan.jeepay.thirdparty.channel.alipay;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel;
import com.alipay.api.request.AlipayDataDataserviceBillDownloadurlQueryRequest;
import com.alipay.api.response.AlipayDataDataserviceBillDownloadurlQueryResponse;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.CheckBatch;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.bill.ChannelBill;
import com.jeequan.jeepay.core.model.bill.ChannelBillRQ;
import com.jeequan.jeepay.core.model.bill.ChannelBillRS;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvsubMchParams;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.ExcelUtil;
import com.jeequan.jeepay.db.entity.CheckChannelBill;
import com.jeequan.jeepay.thirdparty.channel.AbstractBillDownloadService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;

/*
* 支付宝 对账单下载
*
* @author zx
*
* @date 2021/6/8 17:20
*/
@Slf4j
@Service
public class AlipayBillDownloadService extends AbstractBillDownloadService {

    @Override
    public String getIfCode() {
        return CS.IF_CODE.ALIPAY;
    }

    @Override
    public ChannelBillRS convertStandardBill(ChannelBillRQ channelBillRQ, MchAppConfigContext mchAppConfigContext, Date billDate, String ifCode){

        String logPrefix = "【支付宝对账单下载】";

        ChannelBillRS channelBillRes = new ChannelBillRS();

        AlipayDataDataserviceBillDownloadurlQueryRequest req = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        AlipayDataDataserviceBillDownloadurlQueryModel model = new AlipayDataDataserviceBillDownloadurlQueryModel();
        req.setBizModel(model);

        model.setBillDate(DateUtil.formatDate(billDate));
        model.setBillType("trade");

        String channelMchNo = channelBillRQ.getChannelMchNo(); // 渠道商户号

        // 特约商户， 放置子商户token
        if(mchAppConfigContext.isIsvsubMch()){
            AlipayIsvsubMchParams isvsubMchParams = (AlipayIsvsubMchParams) channelBillRQ.getIsvsubMchParams();
            req.putOtherTextParam("app_auth_token", isvsubMchParams.getAppAuthToken());
        }

        // 账单文件流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        try {
            AlipayDataDataserviceBillDownloadurlQueryResponse resp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(req);
            log.info("{}，返回结果：{}", logPrefix, JSON.toJSONString(resp));
            if (!resp.isSuccess()) {
                throw new BizException(resp.getCode() + "[" + resp.getMsg() + "]，" + resp.getSubCode() + "[" + resp.getSubMsg() + "]");
            }

            // 下载对账单，写入文件输出流
            HttpUtil.download(resp.getBillDownloadUrl(), byteArrayOutputStream, false);

            // 上传oss
            String url = upload2Oss(ifCode, channelMchNo, billDate, ".zip", IoUtil.toStream(byteArrayOutputStream));
            // 生成附带对账文件下载地址的解析成功的批次
            CheckBatch checkBatch = genReleaseSuccessCheckBatch(ifCode, billDate, channelMchNo, url);
            // 渠道账单列表
            List<ChannelBill> channelBillList = new ArrayList<>();
            // 渠道总退款金额
            long channelTotalRefundAmount = 0;

            // 读取对账单 csv文件
            List<MutablePair<ZipEntry, CsvData>> mutablePairs = ExcelUtil.readCsvDataByZipInputStream(IoUtil.toStream(byteArrayOutputStream), CharsetUtil.CHARSET_GBK, CharsetUtil.CHARSET_GBK);

            for (MutablePair<ZipEntry, CsvData> mutablePair : mutablePairs) {
                CsvData data = mutablePair.right;
                List<CsvRow> rows = data.getRows();

                // 汇总数据
                if (mutablePair.left.getName().contains("汇总")) {
                    if (rows.size() > 1) {
                        List<String> rawList = rows.get(1).getRawList();

                        if (rawList.size() > 10) {
                            checkBatch.setChannelTotalCount(Integer.valueOf(rawList.get(2).trim()));
                            checkBatch.setChannelTotalRefundCount(Integer.valueOf(rawList.get(3).trim()));
                            checkBatch.setChannelTotalAmount(AmountUtil.convertDollar2CentLong(rawList.get(4).trim()));
                            checkBatch.setChannelTotalFee(AmountUtil.convertDollar2CentLong(rawList.get(9).trim()));
                        }
                    }

                    // 明细数据
                }else{
                    // 遍历行
                    for (int i = 1; i < rows.size(); i++) {
                        CsvRow csvRow = rows.get(i);
                        // getRawList返回一个List列表，列表的每一项为CSV中的一个单元格
                        List<String> rawList = csvRow.getRawList();

                        if (rawList.size() > 22) {
                            ChannelBill channelBill = new ChannelBill();
                            channelBill.setBatchNo(checkBatch.getBatchNo());
                            channelBill.setBillDate(billDate);
                            channelBill.setIfCode(ifCode);
                            channelBill.setChannelMchNo(channelMchNo);
                            channelBill.setChannelOrderNo(rawList.get(0).trim());
                            channelBill.setChannelAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(11).trim())));
                            channelBill.setChannelFeeAmount(Math.abs(AmountUtil.convertDollar2CentLong(rawList.get(22).trim())));
                            channelBill.setChannelSuccessAt(DateUtil.parseDateTime(rawList.get(5).trim()));
                            channelBill.setChannelUser(rawList.get(10).trim());

                            if (StringUtils.equals(rawList.get(2).trim(), "交易")) {
                                channelBill.setOrderId(rawList.get(1).trim());
                                channelBill.setBillType(CheckChannelBill.BILL_TYPE_PAY);
                                channelBill.setChannelState((byte) 2);
                            }else if (StringUtils.equals(rawList.get(2).trim(), "退款")) {
                                channelBill.setOrderId(rawList.get(21).trim()); // 平台退款订单号
                                channelBill.setBillType(CheckChannelBill.BILL_TYPE_REFUND);
                                channelBill.setChannelState((byte) 5);
                                channelBill.setOrgPayOrderId(rawList.get(1).trim());

                                channelTotalRefundAmount += channelBill.getChannelAmount();
                            }else {
                                log.error("支付宝账单类型错误！");
                                continue;
                            }

                            channelBillList.add(channelBill);
                        }
                    }
                }
            }

            checkBatch.setChannelTotalRefundAmount(channelTotalRefundAmount);
            checkBatch.setChannelTotalAmount(checkBatch.getChannelTotalAmount() + Math.abs(channelTotalRefundAmount));

            channelBillRes.setCheckBatch(checkBatch);
            channelBillRes.setChannelBillList(channelBillList);

            return channelBillRes;
        }catch (Exception e) {
            log.error("{}, 解析对账文件失败，", logPrefix, e);
            channelBillRes.setCheckBatch(genReleaseFailCheckBatch(ifCode, billDate, channelMchNo, e.getMessage()));
            return channelBillRes;
        }finally {
            IoUtil.close(byteArrayOutputStream);
        }
    }

}
