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

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.thinkunion.park.service.common.utils.AmtUtil;
import com.yuchen.saas.manage.user.api.entity.User;
import com.yuchen.saas.manage.user.api.feign.IUserClient;
import com.yuchen.saas.park.api.dto.property.*;
import com.yuchen.saas.park.api.entity.property.PropertyShareFee;
import com.yuchen.saas.park.api.entity.property.PropertyShareFeeDetail;
import com.yuchen.saas.park.api.enums.property.CreateBillTypeEnum;
import com.yuchen.saas.park.api.enums.property.ShareTypeEnum;
import com.yuchen.saas.park.api.enums.property.YesOrNoEnum;
import com.yuchen.saas.park.api.vo.property.PropertyShareFeeListVo;
import com.yuchen.saas.park.service.mapper.property.PropertyShareFeeMapper;
import com.yuchen.saas.park.service.service.property.bill.PropertyBillFactoryService;
import org.nest.springwrap.core.log.exception.ServiceException;
import org.nest.springwrap.core.secure.utils.AuthUtil;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 固定分摊金额
 */
@Service
public class PropertyShareFeeService extends ServiceImpl<PropertyShareFeeMapper, PropertyShareFee> {
    @Resource
    private PropertyShareFeeDetailService propertyShareFeeDetailService;
    @Resource
    private PropertySearchParkInfoService propertySearchParkInfoService;
    @Resource
    private IUserClient userClient;
    @Resource
    private PropertyBillFactoryService propertyBillFactoryService;
    @Resource
    private PropertyBillingSettingsService propertyBillingSettingsService;

    /**
     * 分摊金额保存
     *
     * @param shareFeeSaveDto
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveShareFee(PropertyShareFeeSaveDto shareFeeSaveDto) {
        PropertyShareFee shareFee;
        if (Func.isEmpty(shareFeeSaveDto.getId())) {
            shareFee = BeanUtil.copyProperties(shareFeeSaveDto, PropertyShareFee.class);
            shareFee.setCreateTime(new Date());
            shareFee.setCreateUser(AuthUtil.getUserId());
        } else {
            shareFee = this.getById(shareFeeSaveDto.getId());
            if (shareFee.getStatus() == YesOrNoEnum.YES.getValue()) {
                throw new ServiceException("该记录已分摊，不支持修改");
            }
            BeanUtil.copyProperties(shareFeeSaveDto, shareFee);
            shareFee.setUpdateUser(AuthUtil.getUserId());
            shareFee.setUpdateTime(new Date());
        }
        this.saveOrUpdate(shareFee);

        PropertyShareFeeDetailSaveDto detailSaveDto = new PropertyShareFeeDetailSaveDto();
        detailSaveDto.setParkId(shareFeeSaveDto.getParkId());
        detailSaveDto.setShareFeeId(shareFee.getId());
        detailSaveDto.setStrHouseIds(shareFeeSaveDto.getStrHouseIds());
        propertyShareFeeDetailService.saveShareFeeDetail(detailSaveDto);
    }


    /**
     * 分摊金额删除
     *
     * @param shareFeeId
     */
    @Transactional
    public void deleteShareFee(long shareFeeId) {
        PropertyShareFee shareFee = this.getById(shareFeeId);
        if (shareFee.getStatus() == YesOrNoEnum.YES.getValue()) {
            throw new ServiceException("该记录已分摊，不支持删除");
        }
        this.removeById(shareFeeId);
        LambdaQueryWrapper<PropertyShareFeeDetail> qw = new LambdaQueryWrapper<>();
        qw.eq(PropertyShareFeeDetail::getShareFeeId, shareFeeId);
        propertyShareFeeDetailService.remove(qw);
    }


    /**
     * 固定分摊金额列表查询
     *
     * @param qryDto
     * @return
     */
    public Page<PropertyShareFeeListVo> selectPage(PropertyShareFeeQryDto qryDto) {
        Page<PropertyShareFeeListVo> page = new Page<>(qryDto.getCurrent(), qryDto.getSize());
        this.baseMapper.selectShareFeePage(page, this.getPageQueryParam(qryDto));
        this.decoratePage(page.getRecords());
        return page;
    }

    private void decoratePage(List<PropertyShareFeeListVo> records) {
        if (records.size() == 0) {
            return;
        }
        List<Long> tmpUserIds = records.stream().map(PropertyShareFeeListVo::getCreateUser).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> tmpShareUserIds = records.stream().map(PropertyShareFeeListVo::getShareUser).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> userIdList = new ArrayList<>();
        userIdList.addAll(tmpUserIds);
        userIdList.addAll(tmpShareUserIds);
        List<User> userList = userClient.findUserListByUserIds(userIdList).getData();

        records.forEach(record -> {
            if (userList != null) {
                userList.forEach(user -> {
                    if (record.getCreateUser().equals(user.getId())) {
                        record.setCreateName(user.getName());
                    }
                    if (Func.isNotEmpty(record.getShareUser()) && record.getShareUser().equals(user.getId())) {
                        record.setShareUserName(user.getName());
                    }
                });
            }

        });
    }

    private QueryWrapper<String> getPageQueryParam(PropertyShareFeeQryDto qryDto) {
        QueryWrapper<String> qw = new QueryWrapper<>();
        if (Func.isNotEmpty(qryDto.getParkId())) {
            qw.eq("sf.park_id", qryDto.getParkId());
        } else {
            qw.in("sf.park_id", propertySearchParkInfoService.getParkIdsByCurrUser());
        }
        if (Func.isNotEmpty(qryDto.getStatus())) {
            qw.eq("sf.status", qryDto.getStatus());
        }
        if (Func.isNotEmpty(qryDto.getStartFeeDate())) {
            qw.le("sf.start_date", qryDto.getStartFeeDate());
        }
        if (Func.isNotEmpty(qryDto.getEndFeeDate())) {
            qw.ge("sf.start_date", qryDto.getEndFeeDate());
        }
        if (Func.isNotEmpty(qryDto.getStartFeeDate2())) {
            qw.le("sf.end_date", qryDto.getStartFeeDate2());
        }
        if (Func.isNotEmpty(qryDto.getEndFeeDate2())) {
            qw.ge("sf.end_date", qryDto.getEndFeeDate2());
        }
        if (Func.isNotEmpty(qryDto.getStartShareTime())) {
            qw.le("sf.share_time", qryDto.getStartShareTime());
        }
        if (Func.isNotEmpty(qryDto.getEndShareTime())) {
            qw.ge("sf.share_time", qryDto.getEndShareTime());
        }
        if (Func.isNotEmpty(qryDto.getStartCreateTime())) {
            qw.le("sf.create_time", qryDto.getStartCreateTime());
        }
        if (Func.isNotEmpty(qryDto.getEndCreateTime())) {
            qw.ge("sf.create_time", qryDto.getEndCreateTime());
        }
        qw.orderByDesc("sf.create_time");

        return qw;
    }

    /**
     * 固定金额详情
     *
     * @param shareFeeId
     * @return
     */
    public PropertyShareFeeSaveDto getShareFeeDetail(long shareFeeId) {
        PropertyShareFee shareFee = this.getById(shareFeeId);
        PropertyShareFeeSaveDto view = BeanUtil.copyProperties(shareFee, PropertyShareFeeSaveDto.class);
        List<String> houseIdList = new ArrayList<>();
        AtomicReference<Long> totalShareFen = new AtomicReference<>(0L);
        propertyShareFeeDetailService.lambdaQuery().eq(PropertyShareFeeDetail::getShareFeeId, shareFeeId)
                .list().forEach(item -> {
                    houseIdList.add(String.valueOf(item.getHouseId()));
                    totalShareFen.updateAndGet(v -> v + item.getShareAmtFen());
                });
        if (view != null) {
            view.setTotalAmt(AmtUtil.fenToYuan(shareFee.getTotalAmtFen()));
            view.setShareAmtFen(totalShareFen.get());
            view.setStrHouseIds(String.join(",", houseIdList));
        }
        return view;
    }


    /**
     * 固定金额分摊
     *
     * @param shareFeeId
     */
    @Transactional(rollbackFor = Exception.class)
    public void share(long shareFeeId) {
        PropertyShareFee shareFee = this.getById(shareFeeId);
        if (shareFee.getStatus() == YesOrNoEnum.YES.getValue()) {
            throw new ServiceException("该笔费用状态已分摊");
        }
//        PropertyBillingSettings settings = propertyBillingSettingsService.getBillingSettings(shareFee.getParkId());
        if (shareFee.getShareType() == ShareTypeEnum.BY_USER.getValue()) {
//            int count = propertyShareFeeDetailService
//                    .lambdaQuery().eq(PropertyShareFeeDetail::getShareFeeId, shareFeeId)
//                    .count();
//            // 分摊金额 = 分摊总金额 / 总户数
//            BigDecimal shareAmtYuan = AmtUtil.fenToYuan(shareFee.getTotalAmtFen())
//                    .divide(BigDecimal.valueOf(count), 4, RoundingMode.HALF_UP); //（元，四位小数）
//            shareAmtYuan = propertyBillingSettingsService.getBillAmtByYuan(settings, shareAmtYuan);// 账单设置金额小数位

            LambdaUpdateWrapper<PropertyShareFeeDetail> uw = new LambdaUpdateWrapper<>();
            uw.eq(PropertyShareFeeDetail::getShareFeeId, shareFeeId);
//            uw.set(PropertyShareFeeDetail::getShareAmtFen, AmtUtil.yuanToFen(shareAmtYuan));
            uw.set(PropertyShareFeeDetail::getShareAmtFen, this.getShareAmtFenByUser(shareFeeId));

            propertyShareFeeDetailService.update(uw);
        } else {
//            BigDecimal totalArea = propertyShareFeeDetailService.getShareFeeTotalArea(shareFeeId);
            List<PropertyShareFeeDetail> detailList = propertyShareFeeDetailService.listAreaDetail(shareFeeId);
//            detailList.forEach(detail -> {
//                // 分摊金额 = (房源面积 / totalArea) * 分摊总金额
//                BigDecimal shareAmtYuan = (detail.getConstructionArea().divide(totalArea, 4, RoundingMode.HALF_UP))
//                        .multiply(AmtUtil.fenToYuan(shareFee.getTotalAmtFen()));
//                shareAmtYuan = propertyBillingSettingsService.getBillAmtByYuan(settings, shareAmtYuan);
//                detail.setShareAmtFen(AmtUtil.yuanToFen(shareAmtYuan));
//            });
            this.setShareAmtFenByArea(shareFeeId,detailList);

            propertyShareFeeDetailService.updateBatchById(detailList, 1000);
        }

        shareFee.setShareTime(new Date());
        shareFee.setStatus(YesOrNoEnum.YES.getValue());
        shareFee.setShareUser(AuthUtil.getUserId());
        shareFee.setUpdateUser(AuthUtil.getUserId());
        shareFee.setUpdateTime(new Date());

        this.updateById(shareFee);

        // TODO tucq MQ 生成分摊账单
        List<PropertyShareFeeDetail> list = propertyShareFeeDetailService.lambdaQuery()
                .eq(PropertyShareFeeDetail::getShareFeeId,shareFeeId).list();
        list.forEach(detail -> {
            PropertyShareFeeCreateBillDto shareFeeBillDto = BeanUtil.copyProperties(shareFee,PropertyShareFeeCreateBillDto.class);
            shareFeeBillDto.setShareFeeId(shareFeeId);
            shareFeeBillDto.setHouseId(detail.getHouseId());
            shareFeeBillDto.setShareAmtFen(detail.getShareAmtFen());

            CreateBillDto createBillDto = new CreateBillDto();
            createBillDto.setShareFeeCreateBillDto(shareFeeBillDto);
            createBillDto.setCreateBillTypeEnum(CreateBillTypeEnum.SHARE_FEE);

            propertyBillFactoryService.createBill(createBillDto);
        });

    }

    /**
     * 获取按户计算分摊金额，单位：分
     * @param shareFeeId
     * @return
     */
    public long getShareAmtFenByUser(long shareFeeId) {
        PropertyShareFee shareFee = this.getById(shareFeeId);
        int count = propertyShareFeeDetailService
                .lambdaQuery().eq(PropertyShareFeeDetail::getShareFeeId, shareFeeId)
                .count();
        // 分摊金额 = 分摊总金额 / 总户数
        BigDecimal shareAmtYuan = AmtUtil.fenToYuan(shareFee.getTotalAmtFen())
                .divide(BigDecimal.valueOf(count), 4, RoundingMode.HALF_UP); //（元，四位小数）
        shareAmtYuan = propertyBillingSettingsService.getBillAmtByYuan(shareFee.getParkId(), shareAmtYuan);// 账单设置金额小数位
        return AmtUtil.yuanToFen(shareAmtYuan);
    }

    /**
     * 按面积设置明细分摊金额
     * @param shareFeeId
     * @param detailList
     */
    public void setShareAmtFenByArea(long shareFeeId,List<PropertyShareFeeDetail> detailList) {
        BigDecimal totalArea = propertyShareFeeDetailService.getShareFeeTotalArea(shareFeeId);
        PropertyShareFee shareFee = this.getById(shareFeeId);
        detailList.forEach(detail -> {
            // 分摊金额 = (房源面积 / totalArea) * 分摊总金额
            BigDecimal shareAmtYuan = (detail.getConstructionArea().divide(totalArea, 4, RoundingMode.HALF_UP))
                    .multiply(AmtUtil.fenToYuan(shareFee.getTotalAmtFen()));
            shareAmtYuan = propertyBillingSettingsService.getBillAmtByYuan(shareFee.getParkId(), shareAmtYuan);
            detail.setShareAmtFen(AmtUtil.yuanToFen(shareAmtYuan));
        });
    }


}
