package com.hw.ems.base.service.impl;

import com.hw.common.core.text.Convert;
import com.hw.common.core.utils.DateUtils;
import com.hw.common.core.utils.StringUtils;
import com.hw.common.datascope.annotation.DataScope;
import com.hw.common.security.utils.SecurityUtils;
import com.hw.ems.base.domain.BaseLineLoss;
import com.hw.ems.base.domain.BaseMonitorPublic;
import com.hw.ems.base.domain.BasePublicUser;
import com.hw.ems.base.domain.vo.MonitorVo;
import com.hw.ems.base.domain.vo.PublicManageVo;
import com.hw.ems.base.mapper.BaseMonitorPublicMapper;
import com.hw.ems.base.mapper.BasePublicUserMapper;
import com.hw.ems.base.service.IBasePublicUserService;
import com.hw.ems.report.service.IDataAnalysisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 公摊用户Service业务层处理
 *
 * @author yangwl
 * @date 2023-04-24
 */
@Service
public class BasePublicUserServiceImpl implements IBasePublicUserService {
    @Autowired
    private BasePublicUserMapper basePublicUserMapper;

    @Autowired
    private BaseMonitorPublicMapper baseMonitorPublicMapper;

    @Autowired
    private IDataAnalysisService dataAnalysisService;

    /**
     * 查询公摊用户
     *
     * @param id 公摊用户主键
     * @return 公摊用户
     */
    @Override
    //@DS("#header.poolName")
    public BasePublicUser selectBasePublicUserById(Long id) {
        return basePublicUserMapper.selectBasePublicUserById(id);
    }

    /**
     * 查询公摊用户列表
     *
     * @param basePublicUser 公摊用户
     * @return 公摊用户
     */
    @Override
    @DataScope(deptAlias = "null")
    //@DS("#header.poolName")
    public List<BasePublicUser> selectBasePublicUserList(BasePublicUser basePublicUser) {
        return basePublicUserMapper.selectBasePublicUserList(basePublicUser);
    }

    /**
     * 新增公摊用户
     *
     * @param basePublicUser 公摊用户
     * @return 结果
     */
    //@DS("#header.poolName")
    @Override
    public int insertBasePublicUser(BasePublicUser basePublicUser) {
        basePublicUser.setCreateBy(SecurityUtils.getUsername());
        basePublicUser.setCreateTime(DateUtils.getNowDate());
        int rows = basePublicUserMapper.insertBasePublicUser(basePublicUser);
        insertPublicUserMonitor(basePublicUser);
        return rows;
    }

    public void insertPublicUserMonitor(BasePublicUser basePublicUser) {
        String[] publicShareIds = basePublicUser.getPublicShareIds();
        String[] publicMonitorIds = basePublicUser.getPublicMonitorIds();
        if (StringUtils.isNotNull(publicShareIds)) {
            // 新增
            List<BaseMonitorPublic> list = new ArrayList<BaseMonitorPublic>();
            for (String publicShareId : publicShareIds) {
                BaseMonitorPublic up = new BaseMonitorPublic();
                up.setPublicShareId(basePublicUser.getId());
                up.setMonitorId(publicShareId);
                up.setPublicShareType(1);
                list.add(up);
            }
            for (String publicMonitorId : publicMonitorIds) {
                BaseMonitorPublic up = new BaseMonitorPublic();
                up.setPublicShareId(basePublicUser.getId());
                up.setMonitorId(publicMonitorId);
                up.setPublicShareType(0);
                list.add(up);
            }
            if (list.size() > 0) {
                baseMonitorPublicMapper.batchMonitorPublic(list);
            }
        }
    }

    /**
     * 修改公摊用户
     *
     * @param basePublicUser 公摊用户
     * @return 结果
     */
    @Override
    //@DS("#header.poolName")
    public int updateBasePublicUser(BasePublicUser basePublicUser) {
        baseMonitorPublicMapper.deleteBaseMonitorPublicById(basePublicUser.getId());
        String[] publicShareIds = basePublicUser.getPublicShareIds();
        String[] publicMonitorIds = basePublicUser.getPublicMonitorIds();
        if (StringUtils.isNotNull(publicShareIds)) {
            // 新增
            List<BaseMonitorPublic> list = new ArrayList<BaseMonitorPublic>();
            for (String publicShareId : publicShareIds) {
                BaseMonitorPublic up = new BaseMonitorPublic();
                up.setPublicShareId(basePublicUser.getId());
                up.setMonitorId(publicShareId);
                up.setPublicShareType(1);
                list.add(up);
            }
            for (String publicMonitorId : publicMonitorIds) {
                BaseMonitorPublic up = new BaseMonitorPublic();
                up.setPublicShareId(basePublicUser.getId());
                up.setMonitorId(publicMonitorId);
                up.setPublicShareType(0);
                list.add(up);
            }
            if (list.size() > 0) {
                baseMonitorPublicMapper.batchMonitorPublic(list);
            }
        }
        basePublicUser.setUpdateTime(DateUtils.getNowDate());
        return basePublicUserMapper.updateBasePublicUser(basePublicUser);
    }

    /**
     * 批量删除公摊用户
     *
     * @param ids 需要删除的公摊用户主键
     * @return 结果
     */
    @Override
    //@DS("#header.poolName")
    public int deleteBasePublicUserByIds(String ids) {
        return basePublicUserMapper.deleteBasePublicUserByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除公摊用户信息
     *
     * @param id 公摊用户主键
     * @return 结果
     */
    @Override
    //@DS("#header.poolName")
    public int deleteBasePublicUserById(Long id) {
        return basePublicUserMapper.deleteBasePublicUserById(id);
    }

    @Override
    //@DS("#header.poolName")
    public List<MonitorVo> selectlistChild(Long id) {
        return basePublicUserMapper.selectlistChild(id);
    }

    @Override
    //@DS("#header.poolName")
    public List<BasePublicUser> selectPublicUserList(PublicManageVo publicManageVo, BigDecimal sumPublicExpend) {
        //面积分摊
        List<BasePublicUser> basePublicUsers = basePublicUserMapper.selectPublicUserList(Convert.toStrArray(publicManageVo.getIds()));
        BigDecimal sumExpend = new BigDecimal(0);
        //每个公共表下挂所属用户List，根据分摊类型计算公摊比率
        Map<String, List<BasePublicUser>> monitorIdMap = new HashMap<>();
        for (BasePublicUser basePublicUser : basePublicUsers) {
            if (basePublicUser.getMonitors().size() == 0) {
                basePublicUser.setUserExpend(new BigDecimal(0));
                basePublicUser.setPublicExpend(new BigDecimal(0));
                continue;
            }
            //公摊表与用户存储关系
            String[] monitorIdList = basePublicUser.getMonitors().stream().peek(e -> {
                        //0-公共表用户存入表具
                        if (e.getPublicShareType() == 0) {
                            if (monitorIdMap.containsKey(e.getMonitorId())) {
                                List<BasePublicUser> publicUsers = monitorIdMap.get(e.getMonitorId());
                                publicUsers.add(basePublicUser);
                                monitorIdMap.put(e.getMonitorId(), publicUsers);
                            } else {
                                ArrayList<BasePublicUser> publicUsers = new ArrayList<>();
                                publicUsers.add(basePublicUser);
                                monitorIdMap.put(e.getMonitorId(), publicUsers);
                            }
                            if (publicManageVo.getShareType() == 2L) {
                                BigDecimal publicExpend = basePublicUserMapper.queryPublicMonitorDnbExpend(new String[]{e.getMonitorId()}, publicManageVo.getStartTime(), publicManageVo.getEndTime());
                                e.setMonitorExpend(publicExpend);
                            } else if (publicManageVo.getShareType() == 3L) {
                                BigDecimal publicExpend = basePublicUserMapper.queryPublicMonitorWaterExpend(new String[]{e.getMonitorId()}, publicManageVo.getStartTime(), publicManageVo.getEndTime());
                                e.setMonitorExpend(publicExpend);
                            }
                        }
                    }).filter(e -> e.getPublicShareType() == 1)
                    .map(MonitorVo::getMonitorId).toArray(String[]::new);
            //计算各用户能耗
            if (publicManageVo.getShareType() == 2L) {
                BigDecimal userExpend = basePublicUserMapper.queryPublicMonitorDnbExpend(monitorIdList, publicManageVo.getStartTime(), publicManageVo.getEndTime());
                sumExpend = sumExpend.add(userExpend);
                basePublicUser.setUserExpend(userExpend);
            } else if (publicManageVo.getShareType() == 3L) {
                BigDecimal userExpend = basePublicUserMapper.queryPublicMonitorWaterExpend(monitorIdList, publicManageVo.getStartTime(), publicManageVo.getEndTime());
                sumExpend = sumExpend.add(userExpend);
                basePublicUser.setUserExpend(userExpend);
            }
        }

        //公摊分析
        return basePublicUsersAnalysis(monitorIdMap, basePublicUsers, publicManageVo, sumPublicExpend);
    }

    /**
     * 分析每个用户下公摊表的能耗
     *
     * @param monitorIdMap
     * @param basePublicUsers
     * @param publicManageVo
     * @return
     */
    //@DS("#header.poolName")
    private List<BasePublicUser> basePublicUsersAnalysis(Map<String, List<BasePublicUser>> monitorIdMap, List<BasePublicUser> basePublicUsers, PublicManageVo publicManageVo, BigDecimal sumPublicExpend) {
        //shareRule 1-能耗分摊 2-面积分摊 4- 综合分摊
        Long shareRule = publicManageVo.getShareRule();

        //percentage 初步比率：每个用户根据公摊规则下的比率
        if (shareRule == 1L) {
            for (String monitorId : monitorIdMap.keySet()) {
                List<BasePublicUser> publicUsers = monitorIdMap.get(monitorId);
                BigDecimal sumUserExpend = publicUsers.stream().map(BasePublicUser::getUserExpend)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                for (BasePublicUser publicUser : publicUsers) {
                    BigDecimal monitorExpendRate = publicUser.getUserExpend().divide(sumUserExpend, 6, RoundingMode.HALF_UP);
                    for (MonitorVo monitor : publicUser.getMonitors()) {
                        if (monitor.getMonitorId().equals(monitorId)) {
                            monitor.setMonitorExpendRate(monitorExpendRate);
                        }
                    }
                }
            }
        }

        //面积公摊 计算公摊比率
        if (shareRule == 2L || shareRule == 4L) {
            for (String monitorId : monitorIdMap.keySet()) {
                List<BasePublicUser> publicUsers = monitorIdMap.get(monitorId);
                BigDecimal sumArea = publicUsers.stream().map(BasePublicUser::getArea)
                        .map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);
                for (BasePublicUser publicUser : publicUsers) {
                    BigDecimal monitorExpendRate = BigDecimal.valueOf(publicUser.getArea()).divide(sumArea, 6, RoundingMode.HALF_UP);
                    for (MonitorVo monitor : publicUser.getMonitors()) {
                        if (monitor.getMonitorId().equals(monitorId)) {
                            monitor.setMonitorExpendRate(monitorExpendRate);
                        }
                    }
                }
            }
        }
        //手动分摊
        if (shareRule == 3L) {
            return basePublicUsers;
        }

        // 客户本月公共能耗(用电) 使用量 = 公共设施设备用电分摊量+公共设施设备用电损耗分摊量
        // 公共设施设备用电量分摊方式: 消防(系统用电) 及安防(监控、电子围栏、道闸等) 设施设备、公共区域照明设备等公共设备用电按照面积分摊。
        // 客户本月公共设施设备用电分摊量 = 园区本月公共设施设备用电总量 X 该客户租赁面积 / 园区总租凭面积
        // 公共设施设备用电损耗量分摊方式: 公共区域设备设施线路损耗、变压器无功损耗电量按客户用电比例分摊
        // 该客户本月公共设施设备用电损耗分摊量 = 园区本月公共设施设备线损总量 X 该客户本月用水量 / 园区各客户本月使用总量
        if (shareRule == 4L) {
            BaseLineLoss baseLineLoss = new BaseLineLoss();
            Map<String, Object> lineLossMap = new HashMap<>();
            lineLossMap.put("beginCollectTime", publicManageVo.getStartTime());
            lineLossMap.put("endCollectTime", publicManageVo.getEndTime());
            baseLineLoss.setParams(lineLossMap);
            baseLineLoss.setMonitorType(publicManageVo.getShareType());
            List<Map<String, String>> lossMaps = dataAnalysisService.lineLossAnalysisData(baseLineLoss);
            if (lossMaps.size() > 0) {
                for (String monitorId : monitorIdMap.keySet()) {
                    for (Map<String, String> lossMap : lossMaps) {
                        String monitorIdLoss = String.valueOf(lossMap.get("monitorId"));
                        if (monitorId.equals(monitorIdLoss)) {
                            List<BasePublicUser> publicUsers = monitorIdMap.get(monitorId);
                            BigDecimal sumUserExpend = publicUsers.stream().map(BasePublicUser::getUserExpend)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                            for (BasePublicUser publicUser : publicUsers) {
                                BigDecimal monitorExpendRate = publicUser.getUserExpend().divide(sumUserExpend, 6, RoundingMode.HALF_UP);
                                String lossUsage = lossMap.get("lossUsage");
                                BigDecimal multiply = monitorExpendRate.multiply(new BigDecimal(lossUsage));
                                publicUser.setPublicExpend(publicUser.getPublicExpend().add(multiply).setScale(2, RoundingMode.HALF_UP));
                            }
                        }
                    }
                }
            }
        }

        // 计算每个用户公共表 耗量比率和耗量
        for (BasePublicUser basePublicUser : basePublicUsers) {
            for (MonitorVo monitor : basePublicUser.getMonitors()) {
                if (monitor.getPublicShareType() == 0 && Long.valueOf(monitor.getMonitorType()).equals(publicManageVo.getShareType())) {
                    BigDecimal multiply = monitor.getMonitorExpendRate().multiply(monitor.getMonitorExpend()).setScale(2, RoundingMode.HALF_UP);
                    BigDecimal publicExpend = basePublicUser.getPublicExpend();
                    basePublicUser.setPublicExpend(publicExpend.add(multiply));
                }
            }
            if (sumPublicExpend.compareTo(new BigDecimal(0)) > 0) {
                basePublicUser.setPercentage(basePublicUser.getPublicExpend().multiply(new BigDecimal(100)).divide(sumPublicExpend, 2, RoundingMode.HALF_UP));
            }
        }
        return basePublicUsers;
    }


}
