package com.kcim.service.impl;

import com.kcim.common.constants.NumberConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.SnowflakeUtil;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.CostCostingGroup;
import com.kcim.dao.model.FreeCostMap;
import com.kcim.dao.model.ShareParamValue;
import com.kcim.dao.repository.*;
import com.kcim.service.FreeCostService;
import com.kcim.service.ResponsibilityService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @program: CostAccount
 * @description:
 * @author: Wang.YS
 * @create: 2024-04-03 14:19
 **/
@Service("FreeCostService")
@Slf4j
@AllArgsConstructor
public class FreeCostServiceImpl implements FreeCostService {
    FreeCostMapRepository repository;

    AccountingRepository accountingRepository;

    CostShareParamRepository costShareParamRepository;

    CostCostingGroupRepository costCostingGroupRepository;

    ShareParamValueRepository shareParamValueRepository;

    ResponsibilityService responsibilityService;

    @Override
    public Object getList(String filter) {
        return repository.getList(filter);
    }

    /**
     * @param freeCostMap
     * @return
     */
    @Override
    public void addFreeCost(FreeCostMap freeCostMap) {
        freeCostMap.setHospId(UserContext.getHospId());
        freeCostMap.setCreateTime(new Date());
        freeCostMap.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        repository.save(freeCostMap);
    }

    /**
     * @param freeCostMap
     */
    @Override
    public void editFreeCost(FreeCostMap freeCostMap) {
        Integer id = freeCostMap.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");
        }
        FreeCostMap costMap = repository.getById(id);
        BeanUtil.convertObj(freeCostMap, costMap);
        costMap.setUpdateTime(new Date());
        costMap.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        repository.updateById(costMap);
    }

    /**
     * @param id
     */
    @Override
    public void deleteFreeCost(Integer id) {
        if (id == null) {
            throw new CostException("删除时主键必填");
        }
        FreeCostMap costMap = repository.getById(id);
        costMap.setDeleteTime(new Date());
        costMap.setDeleteUser(String.valueOf(UserContext.getCurrentUser().getId()));
        repository.updateById(costMap);
        repository.removeById(id);
    }

    @Override
    public Object getAccountList(String filter) {
        return accountingRepository.getBaseCostList(filter);
    }

    @Override
    public Object getShareParamList(String filter) {
        return costShareParamRepository.getList(filter);
    }

    @Override
    public void computeFreeCost(String computeDate) {
        /*
          1 查询导入的成本数据 有 计算 无退出
          2 通过闲置成本配置表找到对应成本项目数据 其他不计算
          3 判断找到的闲置成本项目是否在当月已计算过  计算过合计需相加  未计算 取原成本项目
          4 总额=闲置成本项目金额+设备成本项目金额
          5 设备负荷系数=实际检查时间参数数值/可检查时间参数数值
          6 设备成本项目金额=总额*设备负荷系数
          7 闲置成本项目金额=总额-设备成本项目金额
          8 未计算过 原数据更新 闲置成本添加 已计算过所有数据更新
          9 原数据进行拆分更新
         */

        List<CostCostingGroup> list = costCostingGroupRepository.getList(computeDate);
        if (CollectionUtils.isEmpty(list)) {
            //成本数据未导入
            throw new CostException("未导入成本数据，无法计算闲置成本");
        }

        //获取所有闲置成本配置
        List<FreeCostMap> freeCostMaps = repository.getList(null);
        if (CollectionUtils.isEmpty(freeCostMaps)) {
            throw new CostException("未进行闲置成本对照，无法计算闲置成本");
        }
        List<ShareParamValue> shareParamValues = shareParamValueRepository.getList(computeDate);
        Map<String, Map<String, BigDecimal>> shareParamValueMap = new HashMap<>();

        if (!CollectionUtils.isEmpty(shareParamValues)) {
            Map<String, List<ShareParamValue>> collect = shareParamValues.stream().collect(Collectors.groupingBy(ShareParamValue::getResponsibilityCode));
            for (String s : collect.keySet()) {
                List<ShareParamValue> shareParamValues1 = collect.get(s);
                Map<String, BigDecimal> map = shareParamValues1.stream().collect(Collectors.toMap(ShareParamValue::getShareParamCode, ShareParamValue::getValueNum, (a, b) -> b));
                shareParamValueMap.put(s, map);
            }
        }

        //对照的会计科目为主键获取负荷系数

        //提取所有设置成本 项目code
        List<String> accountCodes = freeCostMaps.stream().map(FreeCostMap::getAccountCode).collect(Collectors.toList());

        List<CostCostingGroup> collect = list.stream().filter(f -> f.getComputeType().equals(NumberConstant.ONE)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)) {
            //已计算过 需要多一步处理原数据和现数据加起来计算总额
            //上次计算过的数据
            List<CostCostingGroup> lastCompute = list.stream().filter(f -> f.getComputeConnectId() != null).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(lastCompute)) {
                list.removeAll(lastCompute);
                //其他数据按原未计算过时计算
                List<CostCostingGroup> collect1 = list.stream().filter(f -> accountCodes.contains(f.getAccountCode())).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(collect1)) {
                    Map<String, List<CostCostingGroup>> costAccountGroup = collect1.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode));
                    List<CostCostingGroup> saveList = new ArrayList<>();
                    List<CostCostingGroup> updateList = new ArrayList<>();
                    for (FreeCostMap freeCostMap : freeCostMaps) {
                        List<CostCostingGroup> costCostingGroups = costAccountGroup.get(freeCostMap.getAccountCode());
                        if (!CollectionUtils.isEmpty(costCostingGroups)) {
                            for (CostCostingGroup costCostingGroup : costCostingGroups) {
                                if (!CollectionUtils.isEmpty(shareParamValueMap)) {
                                    Map<String, BigDecimal> map = shareParamValueMap.get(costCostingGroup.getResponsibilityCode());
                                    if (CollectionUtils.isEmpty(map)) {
                                        continue;
                                    }
                                    //可检查时间参数
                                    BigDecimal can = map.get(freeCostMap.getCanParamCode());
                                    if (can == null||can.compareTo(BigDecimal.ZERO)==0) {
                                        continue;
                                    }

                                    Long id = SnowflakeUtil.getId();
                                    //实际检查时间参数
                                    BigDecimal actual = map.get(freeCostMap.getActualParamCode());
                                    BigDecimal divide = actual.divide(can, 4, RoundingMode.HALF_UP);
                                    BigDecimal amount = costCostingGroup.getAmount();
                                    BigDecimal multiply = amount;
                                    if(divide.compareTo(BigDecimal.ONE)<0){
                                        multiply = amount.multiply(divide);
                                    }
                                    CostCostingGroup freeCost = BeanUtil.convertObj(costCostingGroup, CostCostingGroup.class);
                                    costCostingGroup.setAmount(multiply);
                                    costCostingGroup.setRate(divide);
                                    costCostingGroup.setComputeConnectId(id);
                                    updateList.add(costCostingGroup);
                                    freeCost.setAmount(amount.subtract(multiply));
                                    freeCost.setComputeType(NumberConstant.ONE);
                                    freeCost.setComputeConnectId(id);
                                    freeCost.setRate(BigDecimal.ONE.subtract(divide));
                                    freeCost.setId(null);
                                    freeCost.setAccountCode(freeCostMap.getFreeAccountCode());
                                    freeCost.setAccountName(freeCostMap.getFreeAccountName());
                                    freeCost.setResponsibilityCode(freeCostMap.getFreeResponsibilityCode());
                                    freeCost.setResponsibilityName(freeCostMap.getFreeResponsibilityName());
                                    saveList.add(freeCost);
//                            }else {

                                }


                            }

                        }

                    }
                    if (!CollectionUtils.isEmpty(updateList)) {
                        costCostingGroupRepository.updateBatchById(updateList);
                    }
                    if (!CollectionUtils.isEmpty(saveList)) {
                        costCostingGroupRepository.saveBatch(saveList);
                    }

                }

                //已计算过的数据 单独方法处理
                Map<Long, List<CostCostingGroup>> lastComputeGroup = lastCompute.stream().collect(Collectors.groupingBy(CostCostingGroup::getComputeConnectId));
                //取出合计金额
                Map<Long, BigDecimal> totalMap = new HashMap<>();
                for (Long aLong : lastComputeGroup.keySet()) {
                    List<CostCostingGroup> costCostingGroups = lastComputeGroup.get(aLong);
                    AtomicReference<BigDecimal> total = new AtomicReference<>(new BigDecimal("0.0000"));
                    costCostingGroups.forEach(m -> {
                        total.updateAndGet(v -> v.add(m.getAmount()));
                    });
                    totalMap.put(aLong, total.get());
                }
                Map<String, FreeCostMap> accountMap = new HashMap<>();
//                Map<String, FreeCostMap> freeAccountMap = new HashMap<>();
                freeCostMaps.forEach(freeCostMap -> {
                    accountMap.put(freeCostMap.getAccountCode(), freeCostMap);
//                    freeAccountMap.put(freeCostMap.getAccountCode(), freeCostMap);
                });

                List<CostCostingGroup> lastAccount = lastCompute.stream().filter(f -> f.getComputeType().equals(NumberConstant.ZERO)).collect(Collectors.toList());
                List<CostCostingGroup> lastFreeAccount = lastCompute.stream().filter(f -> f.getComputeType().equals(NumberConstant.ONE)).collect(Collectors.toList());

                Map<Long, BigDecimal> freeAmount = new HashMap<>();
                Map<Long, BigDecimal> freeRate = new HashMap<>();
                List<CostCostingGroup> lastUpdateList = new ArrayList<>();
                for (CostCostingGroup costCostingGroup : lastAccount) {
                    if (!CollectionUtils.isEmpty(shareParamValueMap)) {
                        Map<String, BigDecimal> map = shareParamValueMap.get(costCostingGroup.getResponsibilityCode());
                        if (CollectionUtils.isEmpty(map)) {
                            continue;
                        }
                        FreeCostMap freeCostMap = accountMap.get(costCostingGroup.getAccountCode());
                        if(Objects.isNull(freeCostMap)){
                            continue;
                        }
                        //可检查时间参数
                        BigDecimal can = map.get(freeCostMap.getCanParamCode());
                        if (can == null||can.compareTo(BigDecimal.ZERO)==0) {
                            continue;
                        }
                        //实际检查时间参数
                        BigDecimal actual = map.get(freeCostMap.getActualParamCode());
                        BigDecimal divide = actual.divide(can, 4, RoundingMode.HALF_UP);
                        BigDecimal amount = totalMap.get(costCostingGroup.getComputeConnectId());
                        BigDecimal multiply = amount;
                        if(divide.compareTo(BigDecimal.ONE)<0){
                            multiply = amount.multiply(divide);
                        }
                        costCostingGroup.setAmount(multiply);
                        costCostingGroup.setRate(divide);
                        lastUpdateList.add(costCostingGroup);
                        freeAmount.put(costCostingGroup.getComputeConnectId(),amount.subtract(multiply));
                        freeRate.put(costCostingGroup.getComputeConnectId(),BigDecimal.ONE.subtract(divide));
                    }
                }
                for (CostCostingGroup costCostingGroup : lastFreeAccount) {
                    costCostingGroup.setAmount(freeAmount.get(costCostingGroup.getComputeConnectId()));
                    costCostingGroup.setRate(freeRate.get(costCostingGroup.getComputeConnectId()));
                    lastUpdateList.add(costCostingGroup);
                }

                if (!CollectionUtils.isEmpty(lastUpdateList)) {
                    costCostingGroupRepository.updateBatchById(lastUpdateList);
                }
            }


        } else {
            //未计算过直接到原数据作为总额
            //符合条件会计科目的数据 未配置 不计算
            List<CostCostingGroup> collect1 = list.stream().filter(f -> accountCodes.contains(f.getAccountCode())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(collect1)) {
                Map<String, List<CostCostingGroup>> costAccountGroup = collect1.stream().collect(Collectors.groupingBy(CostCostingGroup::getAccountCode));
                List<CostCostingGroup> saveList = new ArrayList<>();
                List<CostCostingGroup> updateList = new ArrayList<>();
                for (FreeCostMap freeCostMap : freeCostMaps) {
                    List<CostCostingGroup> costCostingGroups = costAccountGroup.get(freeCostMap.getAccountCode());
                    if (!CollectionUtils.isEmpty(costCostingGroups)) {
                        for (CostCostingGroup costCostingGroup : costCostingGroups) {
                            if (!CollectionUtils.isEmpty(shareParamValueMap)) {
                                Map<String, BigDecimal> map = shareParamValueMap.get(costCostingGroup.getResponsibilityCode());
                                if (CollectionUtils.isEmpty(map)) {
                                    continue;
                                }
                                //可检查时间参数
                                BigDecimal can = map.get(freeCostMap.getCanParamCode());
                                if (can == null||can.compareTo(BigDecimal.ZERO)==0) {
                                    continue;
                                }
                                Long id = SnowflakeUtil.getId();
                                //实际检查时间参数
                                BigDecimal actual = map.get(freeCostMap.getActualParamCode());
                                BigDecimal divide = actual.divide(can, 4, RoundingMode.HALF_UP);
                                BigDecimal amount = costCostingGroup.getAmount();
                                BigDecimal multiply = amount;
                                if(divide.compareTo(BigDecimal.ONE)<0){
                                    multiply = amount.multiply(divide);
                                }
                                CostCostingGroup freeCost = BeanUtil.convertObj(costCostingGroup, CostCostingGroup.class);
                                costCostingGroup.setAmount(multiply);
                                costCostingGroup.setRate(divide);
                                costCostingGroup.setComputeConnectId(id);
                                updateList.add(costCostingGroup);
                                freeCost.setAmount(amount.subtract(multiply));
                                freeCost.setComputeType(NumberConstant.ONE);
                                freeCost.setComputeConnectId(id);
                                freeCost.setRate(BigDecimal.ONE.subtract(divide));
                                freeCost.setId(null);
                                freeCost.setAccountCode(freeCostMap.getFreeAccountCode());
                                freeCost.setAccountName(freeCostMap.getFreeAccountName());
                                freeCost.setResponsibilityCode(freeCostMap.getFreeResponsibilityCode());
                                freeCost.setResponsibilityName(freeCostMap.getFreeResponsibilityName());
                                saveList.add(freeCost);
//                            }else {

                            }


                        }

                    }

                }
                if (!CollectionUtils.isEmpty(updateList)) {
                    costCostingGroupRepository.updateBatchById(updateList);
                }
                if (!CollectionUtils.isEmpty(saveList)) {
                    costCostingGroupRepository.saveBatch(saveList);
                }


            }


        }

        //


    }

    @Override
    public Object getResponsibilityList(String filter) {
        return responsibilityService.getList(filter);

    }
}
