package com.clx.performance.service.impl.settle;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.performance.component.IdGenerateSnowFlake;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OwnerAccountDao;
import com.clx.performance.dao.OwnerRunningWaterRecordDao;
import com.clx.performance.dao.settle.SettlementOwnerDetailDao;
import com.clx.performance.enums.IdTypeEnum;
import com.clx.performance.enums.OwnerAccountEnum;
import com.clx.performance.enums.settle.SettlementOwnerDetailEnum;
import com.clx.performance.enums.settle.SettlementWayEnum;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.OwnerAccount;
import com.clx.performance.model.OwnerRunningWaterRecord;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.param.pc.owner.PageCarrierSettlementOwnerDetailParam;
import com.clx.performance.param.pc.owner.PageOwnerSettlementOwnerDetailParam;
import com.clx.performance.service.settle.SettlementOwnerDetailService;
import com.clx.performance.struct.settle.SettlementOwnerDetailStruct;
import com.clx.performance.utils.excel.ExcelData;
import com.clx.performance.utils.excel.ExcelField;
import com.clx.performance.utils.excel.ExcelSheet;
import com.clx.performance.utils.excel.ExcelUtil;
import com.clx.performance.vo.pc.carrier.settle.CarrierPageSettlementOwnerDetailVO;
import com.clx.performance.vo.pc.owner.settle.PageOwnerSettlementOwnerDetailVO;
import com.msl.common.result.Result;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author liruixin
 * Date 2023-10-12
 * Time 09:43
 */
@Service
@Slf4j
@AllArgsConstructor
public class SettlementOwnerDetailServiceImpl  implements SettlementOwnerDetailService {

    private final SettlementOwnerDetailDao settlementOwnerDetailDao;
    private final SettlementOwnerDetailStruct settlementOwnerDetailStruct;
    private final IdGenerateSnowFlake idGenerateSnowFlake;
    private final OwnerRunningWaterRecordDao ownerRunningWaterRecordDao;
    private final OwnerAccountDao ownerAccountDao;
    private final OrderChildDao orderChildDao;


    @Override
    public Integer saveSettlementDetail(OrderChild orderChild, OrderGoods orderGoods) {

        SettlementOwnerDetail settlementOwnerDetail = new SettlementOwnerDetail();
        //设置结算方式
        settlementOwnerDetail.setSettlementWay(orderGoods.getSettlementWay());
        settlementOwnerDetail.setChildNo(orderChild.getChildNo());
        settlementOwnerDetail.setOrderGoodsNo(orderChild.getOrderGoodsNo());
        settlementOwnerDetail.setOrderNo(orderChild.getOrderNo());

        settlementOwnerDetail.setOwnerUserNo(orderChild.getOwnerUserNo());
        settlementOwnerDetail.setOwnerName(orderChild.getOwnerName());

        settlementOwnerDetail.setSendAddressId(orderChild.getSendAddressId());
        settlementOwnerDetail.setSendAddress(orderChild.getSendAddress());
        settlementOwnerDetail.setReceiveAddressId(orderChild.getReceiveAddressId());
        settlementOwnerDetail.setReceiveAddress(orderChild.getReceiveAddress());

        settlementOwnerDetail.setGoodsId(orderChild.getGoodsId());
        settlementOwnerDetail.setGoodsName(orderChild.getGoodsName());

        // 运费
        settlementOwnerDetail.setFreightPrice(orderChild.getOrderFreightPrice());     //平台运费
        settlementOwnerDetail.setWeight(weightCalc(orderGoods.getSettlementWay(),orderChild.getLoadNet(), orderChild.getUnloadNet()));
        settlementOwnerDetail.setFreight(freightCalc(settlementOwnerDetail.getFreightPrice(), settlementOwnerDetail.getWeight()));

        // 亏吨
        settlementOwnerDetail.setLossPrice(orderChild.getLossPrice());
        settlementOwnerDetail.setLossWeight(lossWeightCalc(orderChild.getLoadNet(), orderChild.getUnloadNet()));
        settlementOwnerDetail.setLossFreight(lossFreightCalc(settlementOwnerDetail.getLossPrice(), settlementOwnerDetail.getLossWeight()));

        // 预付运费
        BigDecimal ans = settlementOwnerDetail.getFreight().subtract(settlementOwnerDetail.getLossFreight());
        if (ans.compareTo(BigDecimal.ZERO) <= 0) {
            settlementOwnerDetail.setPrepayFreight(BigDecimal.ZERO);
        } else {
            /*List<OwnerRunningWaterRecord> runningWaterRecordList = ownerRunningWaterRecordDao.getOwnerRunningWaterRecord(orderChild.getOrderNo());
            BigDecimal frozen = runningWaterRecordList.stream().filter(item -> {
                return item.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode());
            }).map(OwnerRunningWaterRecord::getAlterationBalance).reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal takeOut = runningWaterRecordList.stream().filter(item -> {
                return item.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.TAKE_OUT.getCode());
            }).map(OwnerRunningWaterRecord::getAlterationBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal subtract = frozen.subtract(takeOut);
            if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
                settlementOwnerDetail.setPrepayFreight(BigDecimal.ZERO);
            }
            if (subtract.subtract(ans).compareTo(BigDecimal.ZERO) >= 0) {
                OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(orderChild.getOwnerUserNo(),
                        OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());

                settlementOwnerDetail.setPrepayFreight(ans);
                //生成扣除流水
                OwnerRunningWaterRecord runningWaterRecord = new OwnerRunningWaterRecord();
                runningWaterRecord.setOwnerUserName(orderChild.getOwnerName());
                runningWaterRecord.setMobile(orderChild.getDriverMobile());
                runningWaterRecord.setCreateBy("系统");
                runningWaterRecord.setOrderId(orderChild.getId());
                runningWaterRecord.setOrderNo(orderChild.getOrderNo());

                runningWaterRecord.setRelationId(null);
                runningWaterRecord.setAlterationBalance(ans);
                runningWaterRecord.setFrozenBalance(ans);
                runningWaterRecord.setUsableBalance(account.getUsableBalance());
                runningWaterRecord.setTakeOutBalance(BigDecimal.ZERO);
                runningWaterRecord.setAccountBalance(account.getAccountBalance());
                runningWaterRecord.setOwnerUserNo(account.getOwnerUserNo());

                runningWaterRecord.setAccountType(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());
                runningWaterRecord.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.TAKE_OUT.getCode());
                runningWaterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.TAKE_OUT.getCode()));
                ownerRunningWaterRecordDao.saveEntity(runningWaterRecord);
            } else {
                settlementOwnerDetail.setPrepayFreight(BigDecimal.ZERO);
            }*/
        }

//        // 开票金额
//        settlementOwnerDetail.setInvoiceFreight(invoiceFreightCalc(orderGoods.getSettlementWay(),settlementOwnerDetail));
//
//        // 结算金额
//        settlementOwnerDetail.setSettlementFreight(settlementFreightCalc(orderGoods.getSettlementWay(),settlementOwnerDetail));
//

        settlementOwnerDetail.setFinalPaymentStatus(SettlementOwnerDetailEnum.FinalPaymentStatus.NO.getCode());
        settlementOwnerDetailDao.saveEntity(settlementOwnerDetail);

        return settlementOwnerDetail.getId();
    }

    /**
     * 吨数计算
     */
    private BigDecimal weightCalc(Integer settlementWay,BigDecimal loadNet, BigDecimal unLoadNet){
        if(Objects.equals(settlementWay, SettlementWayEnum.WayType.LOAD.getCode())){ //如果该货主的结算方式为“装车净重”时，那么实际净重=装车净重。
            return loadNet;
        }else{ //如果货主的结算方式为“卸车净重”时，那么实际净重=卸车净重。如果卸车净重>装车净重，那么卸车净重=装车净重。
            return unLoadNet.compareTo(loadNet) > 0? loadNet : unLoadNet;
        }
    }

    /**
     *  运费计算
     */
    public BigDecimal freightCalc(BigDecimal freightPrice, BigDecimal weight){

        return freightPrice.multiply(weight).setScale(0, RoundingMode.HALF_UP);
    }

    /**
     * 亏吨计算
     */
    private BigDecimal lossWeightCalc(BigDecimal loadNet, BigDecimal unLoadNet){
        return unLoadNet.compareTo(loadNet) < 0? loadNet.subtract(unLoadNet) : BigDecimal.ZERO;
    }

    /**
     * 亏吨运费
     */
    private BigDecimal lossFreightCalc(BigDecimal freightPrice, BigDecimal weight){
        return freightPrice.multiply(weight).setScale(0, RoundingMode.HALF_UP);

    }

    /**
     * 开票金额
     */
    private BigDecimal invoiceFreightCalc(Integer settlementWay,SettlementOwnerDetail settlementOwnerDetail){
        if(Objects.equals(settlementWay, SettlementWayEnum.WayType.LOAD.getCode())){ //订单结算方式为“装车净重”时，开票金额=实际净重*平台运费报价-货损金额。
            return settlementOwnerDetail.getWeight().multiply(settlementOwnerDetail.getFreightPrice())
                    .subtract(settlementOwnerDetail.getLossFreight());
        }else{ //订单结算方式为“卸车净重”时，开票金额=实际净重*平台运费报价。
            return settlementOwnerDetail.getWeight().multiply(settlementOwnerDetail.getFreightPrice());
        }
    }

    /**
     * 结算金额
     */
    private BigDecimal settlementFreightCalc(Integer settlementWay,SettlementOwnerDetail settlementOwnerDetail){
        if(Objects.equals(settlementWay, SettlementWayEnum.WayType.LOAD.getCode())){ //订单结算方式为“装车净重”时，结算金额=实际净重*平台运费报价-预付运费-货损金额。
            return settlementOwnerDetail.getWeight().multiply(settlementOwnerDetail.getFreightPrice())
                    .subtract(settlementOwnerDetail.getPrepayFreight()).subtract(settlementOwnerDetail.getLossFreight());
        }else{ //订单结算方式为“卸车净重”时，结算金额=实际净重*平台运费报价-预付运费
            return settlementOwnerDetail.getWeight().multiply(settlementOwnerDetail.getFreightPrice()).subtract(settlementOwnerDetail.getPrepayFreight());
        }
    }

    @Override
    public IPage<CarrierPageSettlementOwnerDetailVO> pageSettlementOwnerDetail(
            PageCarrierSettlementOwnerDetailParam param) {
        IPage<SettlementOwnerDetail> result = settlementOwnerDetailDao.pageSettlementOwnerDetail(param);
        List<CarrierPageSettlementOwnerDetailVO> list = settlementOwnerDetailStruct.covertList(result.getRecords());
        return new Page<CarrierPageSettlementOwnerDetailVO>().setRecords(list).setTotal(result.getTotal()).setPages(result.getPages());
    }

    @Override
    public IPage<PageOwnerSettlementOwnerDetailVO> pageOwnerSettlementOrderDetailList(PageOwnerSettlementOwnerDetailParam param) {

        IPage<SettlementOwnerDetail> settlementOwnerDetail = settlementOwnerDetailDao.pageOwnerSettlementOrderDetailList(param);
        List<PageOwnerSettlementOwnerDetailVO> list = settlementOwnerDetailStruct.covertToOwnerList(settlementOwnerDetail.getRecords());
        return new Page<PageOwnerSettlementOwnerDetailVO>().setRecords(list).setTotal(settlementOwnerDetail.getTotal()).setPages(settlementOwnerDetail.getPages());

    }

    @Override
    public SXSSFWorkbook exportOwnerSettlementOrderDetail(PageOwnerSettlementOwnerDetailParam param) {
        param.setPage(1);
        param.setPageSize(1000000);
        IPage<PageOwnerSettlementOwnerDetailVO> settlementOwnerDetail = pageOwnerSettlementOrderDetailList(param);

        List<PageOwnerSettlementOwnerDetailVO> list = settlementOwnerDetail.getRecords();

        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "序号", "index", 2000));
        fieldList.add(new ExcelField(1, "运单编号", "childNo", 5000));
        fieldList.add(new ExcelField(2, "货主编码", "ownerUserNno", 5000));
        fieldList.add(new ExcelField(3, "货物名称", "goodsName", 5000));

        fieldList.add(new ExcelField(4, "实际净重（吨）", "weight", 5000));
        fieldList.add(new ExcelField(5, "平台运费报价", "freightPrice", 5000));
        fieldList.add(new ExcelField(6, "实际运费金额", "freight", 5000));
        fieldList.add(new ExcelField(7, "货损吨数", "lossWeight", 5000));
        fieldList.add(new ExcelField(8, "货损单价", "lossPrice", 5000));
        fieldList.add(new ExcelField(9, "货损金额", "lossFreight", 5000));
        fieldList.add(new ExcelField(10, "预付运费金额", "prepayFreight", 5000));
        fieldList.add(new ExcelField(11, "结算金额", "settlementFreight", 5000));
        fieldList.add(new ExcelField(12, "开票金额", "invoiceFreight", 5000));

        fieldList.add(new ExcelField(13, "开票标识", "invoiceType", 5000));
        fieldList.add(new ExcelField(14, "订单编号", "orderNo", 5000));
        fieldList.add(new ExcelField(15, "结算单号", "settlementNo", 15000));
        fieldList.add(new ExcelField(16, "结算子单号", "settlementSubNo", 15000));
        fieldList.add(new ExcelField(17, "创建时间", "createTime", 5000));
        fieldList.add(new ExcelField(18, "是否已付尾款", "finalPaymentStatus", 5000));
        fieldList.add(new ExcelField(19, "是否已开票", "invoiceStatus", 5000));

        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (int i=0; i<list.size(); i++){

            PageOwnerSettlementOwnerDetailVO dto = list.get(i);
            List<ExcelData> rowData = new ArrayList<>();

            rowData.add(new ExcelData(i+1));
            rowData.add(new ExcelData(dto.getChildNo()));
            rowData.add(new ExcelData(dto.getOwnerUserNo()+""));
            rowData.add(new ExcelData(dto.getGoodsName()));

            rowData.add(new ExcelData(dto.getWeight()));
            rowData.add(new ExcelData(dto.getFreightPrice().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getLossWeight()));
            rowData.add(new ExcelData(dto.getLossPrice().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getLossFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getPrepayFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getSettlementFreight().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getInvoiceFreight().movePointLeft(2)));

            rowData.add(new ExcelData(dto.getInvoiceTypeMsg()));
            rowData.add(new ExcelData(dto.getOrderNo()));
            rowData.add(new ExcelData(dto.getSettlementNo()));
            rowData.add(new ExcelData(dto.getSettlementSubNo()));
            rowData.add(new ExcelData(dto.getCreateTime()));
            rowData.add(new ExcelData(dto.getFinalPaymentStatusMsg()));
            rowData.add(new ExcelData(dto.getInvoiceStatusMsg()));


            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("货主结算运单明细", "货主结算运单明细", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }

    @Override
    public Integer getInvoiceType(String orderNo) {
        return settlementOwnerDetailDao.getInvoiceType(orderNo);
    }

    @Override
    public Boolean thawAndLockSettlement(String orderNo) {
        boolean orderChildrenFlag = false;
        boolean ownerDetailsFlag = false;
        List<OrderChild> orderChildren = orderChildDao.selectInTransitOrderChildLtUnsettle(orderNo);
        List<SettlementOwnerDetail> ownerDetails = settlementOwnerDetailDao.selectListByOrderNo(orderNo);
        if (CollectionUtil.isNotEmpty(ownerDetails)) {
            ownerDetailsFlag = true;
        }

        if (CollectionUtil.isNotEmpty(orderChildren)) {
            orderChildrenFlag = true;
        }

        if (ownerDetailsFlag || orderChildrenFlag) {
            return true;
        } else {
            return false;
        }
    }
}
