package com.yuchen.saas.park.service.service.property.bill;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuchen.saas.park.api.dto.property.PropertyBillPageQryDto;
import com.yuchen.saas.park.api.entity.park.PmgBatParkInfo;
import com.yuchen.saas.park.api.entity.property.PropertyBill;
import com.yuchen.saas.park.api.entity.property.PropertyBillSub;
import com.yuchen.saas.park.api.entity.property.PropertyFeeMode;
import com.yuchen.saas.park.api.enums.property.BillStatusEnum;
import com.yuchen.saas.park.api.enums.property.ClientFeeModeEnum;
import com.yuchen.saas.park.api.enums.property.ExportBillTypeEnum;
import com.yuchen.saas.park.api.enums.property.YesOrNoEnum;
import com.yuchen.saas.park.api.vo.property.*;
import com.yuchen.saas.park.service.event.property.SetCustomerInfoEvent;
import com.yuchen.saas.park.service.event.property.SetFeeItemNameEvent;
import com.yuchen.saas.park.service.mapper.property.PropertyBillMapper;
import com.yuchen.saas.park.service.service.PmgBatParkInfoService;
import com.yuchen.saas.park.service.service.property.*;
import lombok.extern.slf4j.Slf4j;
import org.nest.springwrap.core.excel.util.ExcelUtil;
import org.nest.springwrap.core.tool.constant.NestConstant;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 账单查询服务
 */
@Slf4j
@Service
public class PropertyBillSearchService {
    @Resource
    private PropertyBillMapper propertyBillMapper;
    @Resource
    private PropertyHousesService propertyHousesService;
    @Resource
    private PropertySearchParkInfoService propertySearchParkInfoService;
    @Resource
    private PropertyFeeStandardService propertyFeeStandardService;
    @Resource
    private PropertyBillSubService propertyBillSubService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private PropertyFeeModeService propertyFeeModeService;
    @Resource
    private PmgBatParkInfoService parkInfoService;
    @Resource
    private IPropertyDirectReductionService iPropertyDirectReductionService;


    /**
     * 账单列表信息查询 （基础信息）
     *
     * @param qryDto
     * @return
     */
    public Page<PropertyBill> selectBillBaseInfoPage(PropertyBillPageQryDto qryDto) {
        Page<PropertyBill> page = new Page<>(qryDto.getCurrent(), qryDto.getSize());
        propertyBillMapper.selectPage(page, this.getBillPageQueryParam(qryDto));
        if (qryDto.getIsDirectReduction() == YesOrNoEnum.YES.getValue()) { // 查询的时候设置直接减免金额
            page.getRecords().forEach(item -> {
                // TODO tucq 显示直接减免金额，计算规则，查询效率有待优化
                int betweenMonth = Integer.parseInt(String.valueOf(DateUtil.betweenMonth(item.getStartDate(), item.getEndDate(), true)));
                PropertyDirectReductionVo directReductionVo = iPropertyDirectReductionService.getPayReduction(item.getHouseId(),item.getPriceFen(),item.getReceivableAmtFen(),
                        item.getFeeId(),new Date(),betweenMonth,item.getStartDate(),item.getEndDate());
                if (directReductionVo != null) {
                    item.setDirectReductionAmtFen(directReductionVo.getTotalReductionPrice());
                }
            });
        }
        return page;
    }


    /**
     * 账单列表信息查询 (全部信息)
     *
     * @param qryDto
     * @return
     */
    public Page<PropertyBillListVo> selectBillFullInfoPage(PropertyBillPageQryDto qryDto) {
        Page<PropertyBillListVo> page = new Page<>(qryDto.getCurrent(), qryDto.getSize());

        Page<PropertyBill> billPage = this.selectBillBaseInfoPage(qryDto);
        List<PropertyBillListVo> listVoList = BeanUtil.copyToList(billPage.getRecords(), PropertyBillListVo.class);

        page.setTotal(billPage.getTotal());
        page.setRecords(listVoList);

        this.assemblePropertyBillListVo(page.getRecords());
        return page;
    }


    /**
     * 分页查询条件
     *
     * @param qryDto
     * @return
     */
    private LambdaQueryWrapper<PropertyBill> getBillPageQueryParam(PropertyBillPageQryDto qryDto) {
        LambdaQueryWrapper<PropertyBill> qw = new LambdaQueryWrapper<>();
        qw.eq(PropertyBill::getIsDeleted, NestConstant.DB_NOT_DELETED);
        if (Func.isNotEmpty(qryDto.getParkId())) {
            qw.eq(PropertyBill::getParkId, qryDto.getParkId());
        } else {
            qw.in(PropertyBill::getParkId, propertySearchParkInfoService.getParkIdsByCurrUser());
        }
        if (Func.isNotEmpty(qryDto.getBuildingId())) {
            qw.eq(PropertyBill::getBuildingId, qryDto.getBuildingId());
        }
        if (Func.isNotEmpty(qryDto.getHouseId()) && !Long.valueOf(0).equals(qryDto.getHouseId())) {
            qw.eq(PropertyBill::getHouseId, qryDto.getHouseId());
        }
        if (Func.isNotEmpty(qryDto.getFeeItemId())) {
            qw.eq(PropertyBill::getFeeItemId, qryDto.getFeeItemId());
        }
        if (Func.isNotEmpty(qryDto.getFeeId())) {
            qw.eq(PropertyBill::getFeeId, qryDto.getFeeId());
        }
        if (Func.isNotEmpty(qryDto.getBillStatus())) {
            qw.eq(PropertyBill::getBillStatus, qryDto.getBillStatus());
        }
        if (Func.isNotEmpty(qryDto.getBillStatusList())) {
            qw.in(PropertyBill::getBillStatus, qryDto.getBillStatusList());
        }
        if (Func.isNotEmpty(qryDto.getCreateBillTypeList())) {
            qw.in(PropertyBill::getCreateBillType, qryDto.getCreateBillTypeList());
        }
        if (Func.isNotEmpty(qryDto.getStartOutBillTime())) {
            qw.le(PropertyBill::getOutBillTime, qryDto.getStartOutBillTime());
        }
        if (Func.isNotEmpty(qryDto.getEndOutBillTime())) {
            qw.ge(PropertyBill::getOutBillTime, qryDto.getStartOutBillTime());
        }
        if (Func.isNotEmpty(qryDto.getStartReceivableDate())) {
            qw.le(PropertyBill::getReceivableDate, qryDto.getStartReceivableDate());
        }
        if (Func.isNotEmpty(qryDto.getEndReceivableDate())) {
            qw.ge(PropertyBill::getReceivableDate, qryDto.getEndReceivableDate());
        }
        if (Func.isNotEmpty(qryDto.getPayStatus())) {
            qw.eq(PropertyBill::getPayStatus, qryDto.getPayStatus());
        }
        if (Func.isNotEmpty(qryDto.getPayStatusList())) {
            qw.in(PropertyBill::getPayStatus, qryDto.getPayStatusList());
        }
        if (Func.isNotEmpty(qryDto.getBillId())) {
            qw.eq(PropertyBill::getId, qryDto.getBillId());
        }
        if (Func.isNotEmpty(qryDto.getBillIdList())) {
            qw.in(PropertyBill::getId, qryDto.getBillIdList());
        }
        if (Func.isNotEmpty(qryDto.getCustomerId())) {
            qw.in(PropertyBill::getCustomerId, qryDto.getCustomerId()); // TODO tucq 根据客户id返查旧的id
        }
        if (Func.isNotEmpty(qryDto.getFeeIdList())) {
            qw.in(PropertyBill::getFeeId, qryDto.getFeeIdList());
        }
        if (Func.isNotEmpty(qryDto.getOrderByColumn())) {
            // TODO tucq 待优化
            if ("receivable_date".equals(qryDto.getOrderByColumn())) {
                if (qryDto.getIsOrderByAsc() == YesOrNoEnum.YES.getValue()) {
                    qw.orderByAsc(PropertyBill::getReceivableDate);
                } else {
                    qw.orderByDesc(PropertyBill::getReceivableDate);
                }
            }

            if ("out_bill_time".equals(qryDto.getOrderByColumn())) {
                if (qryDto.getBillStatus() == BillStatusEnum.YES_OUT.getValue()) {
                    qw.orderByDesc(PropertyBill::getOutBillTime);
                } else {
                    qw.orderByDesc(PropertyBill::getCreateTime);
                }
            }

        }

//        if (Func.isNotEmpty(qryDto.getIsShowZero()) && qryDto.getIsShowZero() == YesOrNoEnum.NO.getValue()) {
//            // TODO tucq 查询零账单
//        }

        return qw;
    }



    /**
     * 列表信息组装
     *
     * @param records
     */
    private void assemblePropertyBillListVo(List<PropertyBillListVo> records) {
        if (records == null || records.size() == 0) {
            return;
        }
        CopyOptions options = CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true);
        List<Long> houseIdList = records.stream().map(PropertyBillListVo::getHouseId).collect(Collectors.toList());
        List<PropertyHouseParentInfoVo> houseInfoList = propertyHousesService.listHouseParentInfo(houseIdList);

        List<Long> feeIdList = records.stream().map(PropertyBillListVo::getFeeId).collect(Collectors.toList());
        List<PropertyFeeParentInfoVo> feeParentInfoList = propertyFeeStandardService.listFeeParentInfoVo(feeIdList);

        List<Long> billIdList = records.stream().map(PropertyBillListVo::getId).collect(Collectors.toList());
        LambdaQueryWrapper<PropertyBillSub> subQry = new LambdaQueryWrapper<>();
        subQry.in(PropertyBillSub::getBillId, billIdList);
        subQry.select(PropertyBillSub::getBillId, PropertyBillSub::getArrearsReason, PropertyBillSub::getLastCallTime);
        List<PropertyBillSub> subList = propertyBillSubService.list(subQry);
        records.forEach(item -> {
            if (Long.valueOf(0).equals(item.getHouseId())) {
                PmgBatParkInfo pmgBatParkInfo = parkInfoService.getById(item.getParkId());
                item.setParkName(pmgBatParkInfo.getParkName());
            }
            houseInfoList.forEach(info -> {
                if (info.getHouseId().equals(item.getHouseId())) {
                    BeanUtil.copyProperties(info, item, options);
                }
            });

            feeParentInfoList.forEach(info -> {
                if (info.getFeeId().equals(item.getFeeId())) {
                    BeanUtil.copyProperties(info, item, options);
                }
            });

            subList.forEach(info -> {
                if (info.getBillId().equals(item.getId())) {
                    BeanUtil.copyProperties(info, item, options);
                }
            });

        });

        List<Long> customerIdList = records.stream().map(PropertyBillListVo::getCustomerId).collect(Collectors.toList());
        applicationContext.publishEvent(new SetCustomerInfoEvent(records, customerIdList));

    }


    /**
     * 根据追溯id获取账单
     */
    public PropertyBill getBillByRetraceId(Long retraceId) {
        List<PropertyBill> list = this.listBillByRetraceId(retraceId);
        if (Func.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    /**
     * 根据追溯id获取账单
     */
    public List<PropertyBill> listBillByRetraceId(Long retraceId) {
        if (Func.isEmpty(retraceId)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<PropertyBill> qw = new LambdaQueryWrapper<>();
        qw.eq(PropertyBill::getRetraceId, retraceId);
        return propertyBillMapper.selectList(qw);
    }

    /**
     * app端查询缴费账单列表
     * @param qryDto
     * @return
     */
    public Page<PropertyAppPayBilListVo> selectPageAppPayBill(PropertyBillPageQryDto qryDto) {
        Page<PropertyAppPayBilListVo> page = new Page<>(qryDto.getCurrent(), qryDto.getSize());
        PropertyFeeMode feeMode = propertyFeeModeService.getFeeMode(qryDto.getParkId());
        if (feeMode.getClientFeeMode() == ClientFeeModeEnum.ALL.getValue()) {
            propertyBillMapper.selectPageAppBillAll(page, this.getBillPageQueryParam(qryDto));
            if (page.getRecords().size() == 0 || page.getRecords().get(0) == null) {
                page.setRecords(new ArrayList<>());
                return page;
            }
        } else if (feeMode.getClientFeeMode() == ClientFeeModeEnum.FEE_ITEM.getValue()) {
            LambdaQueryWrapper<PropertyBill> qw = this.getBillPageQueryParam(qryDto);
            qw.groupBy(PropertyBill::getFeeItemId);
            propertyBillMapper.selectPageAppBillFeeItem(page, qw);
        } else {
            Page<PropertyBill> tmpPage = this.selectBillBaseInfoPage(qryDto);
            List<PropertyAppPayBilListVo>  records = BeanUtil.copyToList(tmpPage.getRecords(),PropertyAppPayBilListVo.class);
            page.setRecords(records);
            page.setTotal(tmpPage.getTotal());
        }
        page.getRecords().forEach(item -> {
            if (feeMode.getClientFeeMode() == ClientFeeModeEnum.ALL.getValue()) {
                item.setFeeItemName("总费用");
                item.setDetailList(this.getAppPayBilDetailList(qryDto));
            } else if (feeMode.getClientFeeMode() == ClientFeeModeEnum.FEE_ITEM.getValue()) {
                qryDto.setFeeItemId(item.getFeeItemId());
                item.setDetailList(this.getAppPayBilDetailList(qryDto));
            } else {
                // 允许选择任意账单进行缴费，当前记录放进去
                List<PropertyAppPayBilDetailListVo> detailList = new ArrayList<>();
                detailList.add(BeanUtil.copyProperties(item,PropertyAppPayBilDetailListVo.class));
                item.setDetailList(detailList);
            }
            item.setClientFeeMode(feeMode.getClientFeeMode());
        });

        List<Long> feeItemIds = page.getRecords().stream().map(PropertyAppPayBilListVo::getFeeItemId).filter(Objects::nonNull).collect(Collectors.toList());
        applicationContext.publishEvent(new SetFeeItemNameEvent(page.getRecords(),feeItemIds));
        return page;
    }

    private List<PropertyAppPayBilDetailListVo> getAppPayBilDetailList(PropertyBillPageQryDto qryDto) {
        List<PropertyAppPayBilDetailListVo> detailList = BeanUtil.copyToList(this.selectBillBaseInfoPage(qryDto).getRecords(),PropertyAppPayBilDetailListVo.class);
        List<Long> feeItemIdList = detailList.stream().map(PropertyAppPayBilDetailListVo::getFeeItemId).collect(Collectors.toList());
        applicationContext.publishEvent(new SetFeeItemNameEvent(detailList,feeItemIdList));
        return detailList;
    }


//    /**
//     * 查询已出账的缴费账单
//     *
//     * @return
//     */
//    public List<PropertyBill> listOutPayBill(PropertyArrearsBillQryDto qryDto) {
//        LambdaQueryWrapper<PropertyBill> qw = new LambdaQueryWrapper<>();
//        qw.eq(PropertyBill::getBillStatus, BillStatusEnum.YES_OUT.getValue());
//        qw.in(PropertyBill::getPayStatus, PayStatusEnum.getNeedPayStatus());
//        if (Func.isNotEmpty(qryDto.getParkId())) {
//            qw.eq(PropertyBill::getParkId, qryDto.getParkId());
//        } else {
//            qw.in(PropertyBill::getParkId, propertySearchParkInfoService.getParkIdsByCurrUser());
//        }
//        if (Func.isNotEmpty(qryDto.getCustomerId()) && !qryDto.getCustomerId().equals(Long.valueOf("0"))) {
//            qw.eq(PropertyBill::getCustomerId, qryDto.getCustomerId());
//        }
//        if (Func.isNotEmpty(qryDto.getHouseId())) {
//            qw.eq(PropertyBill::getHouseId, qryDto.getHouseId());
//        }
//        if (Func.isNotEmpty(qryDto.getFeeItemId())) {
//            qw.eq(PropertyBill::getFeeItemId, qryDto.getFeeItemId());
//        }
//        if (Func.isNotEmpty(qryDto.getFeeId())) {
//            qw.eq(PropertyBill::getFeeId, qryDto.getFeeId());
//        }
//        if (Func.isNotEmpty(qryDto.getFeeItemBindFeeIdList())) {
//            qw.in(PropertyBill::getFeeId, qryDto.getFeeItemBindFeeIdList());
//        }
//        if (Func.isNotEmpty(qryDto.getBillId())) {
//            qw.eq(PropertyBill::getId, qryDto.getBillId());
//        }
//        if (Func.isNotEmpty(qryDto.getBillIdList())) {
//            qw.in(PropertyBill::getId, qryDto.getBillIdList());
//        }
//        if (qryDto.getIsOrderByAsc() == YesOrNoEnum.YES.getValue()) {
//            qw.orderByAsc(PropertyBill::getReceivableDate);
//        } else {
//            qw.orderByDesc(PropertyBill::getStartDate);
//        }
//        return this.propertyBillMapper.selectList(qw);
//    }


    public void export(PropertyBillPageQryDto qryDto, HttpServletResponse response) {
        //TODO tucq 查询条件限制？ 并发下载，数据量大 容易内存溢出！！
        qryDto.setCurrent(1);
        qryDto.setSize(Integer.MAX_VALUE);
        List<PropertyBillListVo> list = this.selectBillFullInfoPage(qryDto).getRecords();
        String dateStr = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm");
        switch (ExportBillTypeEnum.convert(qryDto.getExportBillType())) {
            case NO_OUT:
                List<PropertyNoOutBillExcelVo> excelVoList = BeanUtil.copyToList(list, PropertyNoOutBillExcelVo.class);
                ExcelUtil.export(response, "未出账单" + dateStr, "未出账单", excelVoList, PropertyNoOutBillExcelVo.class);
                return;
            case ARREARS_FEES:
                List<PropertyArrearsBillExcelVo> excelVoList2 = BeanUtil.copyToList(list, PropertyArrearsBillExcelVo.class);
                ExcelUtil.export(response, "欠费账单" + dateStr, "欠费账单", excelVoList2, PropertyArrearsBillExcelVo.class);
                return;
        }

    }


}
