package org.dromara.zjk.statement.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.zjk.domain.vo.ZjkExpertMoneyInfoVO;
import org.dromara.zjk.mapper.ZjkExpertMoneyInfoMapper;
import org.dromara.zjk.statement.domain.ZjkMoneyAnalyseStatement;
import org.dromara.zjk.statement.domain.ZjkMoneyCollectStatement;
import org.dromara.zjk.statement.domain.ZjkMoneyExpertStatement;
import org.dromara.zjk.statement.enums.MoneyStatementType;
import org.dromara.zjk.statement.mapper.ZjkMoneyAnalyseStatementMapper;
import org.dromara.zjk.statement.mapper.ZjkMoneyCollectStatementMapper;
import org.dromara.zjk.statement.mapper.ZjkMoneyExpertStatementMapper;
import org.dromara.zjk.utils.NumberGenerator;
import org.springframework.stereotype.Service;
import org.dromara.zjk.statement.domain.bo.ZjkMoneyStatementBo;
import org.dromara.zjk.statement.domain.vo.ZjkMoneyStatementVo;
import org.dromara.zjk.statement.domain.ZjkMoneyStatement;
import org.dromara.zjk.statement.mapper.ZjkMoneyStatementMapper;
import org.dromara.zjk.statement.service.IZjkMoneyStatementService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 费用报表Service业务层处理
 *
 * @author ygh
 * @date 2024-12-16
 */
@RequiredArgsConstructor
@Service
public class ZjkMoneyStatementServiceImpl implements IZjkMoneyStatementService {

    private final ZjkMoneyStatementMapper baseMapper;
    @Resource
    private ZjkExpertMoneyInfoMapper expertMoneyInfoMapper;
    @Resource
    private ZjkMoneyExpertStatementMapper zjkMoneyExpertStatementMapper;

    @Resource
    private ZjkMoneyCollectStatementMapper zjkMoneyCollectStatementMapper;

    @Resource
    private ZjkMoneyAnalyseStatementMapper zjkMoneyAnalyseStatementMapper;

    /**
     * 查询费用报表
     *
     * @param id 主键
     * @return 费用报表
     */
    @Override
    public ZjkMoneyStatementVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询费用报表列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 费用报表分页列表
     */
    @Override
    public TableDataInfo<ZjkMoneyStatementVo> queryPageList(ZjkMoneyStatementBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ZjkMoneyStatement> lqw = buildQueryWrapper(bo);
        Page<ZjkMoneyStatementVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的费用报表列表
     *
     * @param bo 查询条件
     * @return 费用报表列表
     */
    @Override
    public List<ZjkMoneyStatementVo> queryList(ZjkMoneyStatementBo bo) {
        LambdaQueryWrapper<ZjkMoneyStatement> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ZjkMoneyStatement> buildQueryWrapper(ZjkMoneyStatementBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ZjkMoneyStatement> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getStatementSn() != null, ZjkMoneyStatement::getStatementSn, bo.getStatementSn());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), ZjkMoneyStatement::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getPeriod()), ZjkMoneyStatement::getPeriod, bo.getPeriod());
        lqw.eq(bo.getScopeStartTime() != null, ZjkMoneyStatement::getScopeStartTime, bo.getScopeStartTime());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ZjkMoneyStatement::getStatus, bo.getStatus());
        lqw.eq(bo.getScopeEndTime() != null, ZjkMoneyStatement::getScopeEndTime, bo.getScopeEndTime());
        return lqw;
    }

    /**
     * 新增费用报表
     *
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo() {
        Date[] currentMonthDateRange = DateUtils.getLastMonthDateRange(LocalDate.now());
        Date startTime = currentMonthDateRange[0];
        Date endTime = currentMonthDateRange[1];
        List<String> tenantIds = expertMoneyInfoMapper.selectTenantIds();
        if(CollectionUtil.isEmpty(tenantIds)){
            return true;
        }
        for (String tenantId : tenantIds) {
            extracted(startTime, endTime,MoneyStatementType.monthly.getCode(),tenantId);

        }
        return true;
    }


    /**
     * 修改费用报表
     *
     * @param bo 费用报表
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(ZjkMoneyStatementBo bo) {
        ZjkMoneyStatement update = MapstructUtils.convert(bo, ZjkMoneyStatement.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ZjkMoneyStatement entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除费用报表信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public Boolean addYear() {
        Date[] currentMonthDateRange = DateUtils.getLastYearDateRange(LocalDate.now());
        Date startTime = currentMonthDateRange[0];
        Date endTime = currentMonthDateRange[1];
        List<String> tenantIds = expertMoneyInfoMapper.selectTenantIds();
        if(CollectionUtil.isEmpty(tenantIds)){
            return true;
        }
        for (String tenantId : tenantIds) {
            extracted(startTime, endTime,MoneyStatementType.annualReport.getCode(),tenantId);

        }
        return true;
    }

    private void extracted(Date startTime, Date endTime,String code,String tenantId) {
        ZjkMoneyStatement moneyStatement = new ZjkMoneyStatement();
        moneyStatement.setStatementSn(NumberGenerator.generateUniqueNumber("fee", 8));
        moneyStatement.setType(code);
        moneyStatement.setPeriod(code);
        moneyStatement.setScopeStartTime(startTime);
        moneyStatement.setNameDate(startTime);
        moneyStatement.setTenantId(tenantId);
        moneyStatement.setScopeEndTime(endTime);
        baseMapper.insert(moneyStatement);

        List<ZjkExpertMoneyInfoVO> zjkExpertMoneyInfoList = expertMoneyInfoMapper.selectListByMonth(startTime, endTime, tenantId);


        Map<String, List<ZjkExpertMoneyInfoVO>> expertInfoMap = zjkExpertMoneyInfoList.stream().collect(Collectors.groupingBy(ZjkExpertMoneyInfoVO::getExpertId));
        // 专家费用统计
        List<ZjkMoneyExpertStatement> zjkMoneyExpertStatementList = new ArrayList<>();
        for (String expertId : expertInfoMap.keySet()) {

            {
                List<ZjkExpertMoneyInfoVO> zjkExpertMoneyInfoVOS = expertInfoMap.get(expertId);
                //总费用
                BigDecimal expertTypeMoneyFee = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertTypeMoneyFee).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                //支付金额
                BigDecimal payMoney = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertPayMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);

                //未支付金额

                BigDecimal noPayMoney = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertNoPayMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);

                ZjkExpertMoneyInfoVO zjkExpertMoneyInfoVO = zjkExpertMoneyInfoVOS.stream().findFirst().get();

                ZjkMoneyExpertStatement zjkMoneyExpertStatement = new ZjkMoneyExpertStatement();
                zjkMoneyExpertStatement.setSumFee(expertTypeMoneyFee);
                zjkMoneyExpertStatement.setPayFee(payMoney);
                zjkMoneyExpertStatement.setNoPayFee(noPayMoney);
                zjkMoneyExpertStatement.setExpertName(zjkExpertMoneyInfoVO.getExpertName());
                zjkMoneyExpertStatement.setStatementId(moneyStatement.getId());
                zjkMoneyExpertStatement.setMoneyCycle(zjkExpertMoneyInfoVO.getMoneyCycle());
                zjkMoneyExpertStatement.setExpertType(zjkExpertMoneyInfoVO.getExpertType());

                zjkMoneyExpertStatementList.add(zjkMoneyExpertStatement);
            }
        }

        //汇总
        Map<String, List<ZjkExpertMoneyInfoVO>> moneyCycleMap = zjkExpertMoneyInfoList.stream().collect(Collectors.groupingBy(ZjkExpertMoneyInfoVO::getMoneyCycle));
        List<ZjkMoneyCollectStatement> zjkMoneyCollectStatements = new ArrayList<>();
        for (String moneyCycle : moneyCycleMap.keySet()) {
            List<ZjkExpertMoneyInfoVO> zjkExpertMoneyInfoVOS = moneyCycleMap.get(moneyCycle);
            if (CollectionUtil.isNotEmpty(zjkExpertMoneyInfoVOS)) {
                ZjkMoneyCollectStatement zjkMoneyCollectStatement = new ZjkMoneyCollectStatement();
                zjkMoneyCollectStatement.setMoneyCycle(moneyCycle);
                zjkMoneyCollectStatement.setStatementId(moneyStatement.getId());
                int size = zjkExpertMoneyInfoVOS.stream().collect(Collectors.groupingBy(ZjkExpertMoneyInfoVO::getExpertId)).size();
                zjkMoneyCollectStatement.setExpertCount(size);
                //总费用
                BigDecimal expertTypeMoneyFee = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertTypeMoneyFee).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                //支付金额
                BigDecimal payMoney = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertPayMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                //未支付金额
                BigDecimal noPayMoney = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertNoPayMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                zjkMoneyCollectStatement.setPayMoney(payMoney);
                zjkMoneyCollectStatement.setNoPayMoney(noPayMoney);
                zjkMoneyCollectStatement.setSumFee(expertTypeMoneyFee);
                zjkMoneyCollectStatements.add(zjkMoneyCollectStatement);
            }
        }

        Map<String, List<ZjkExpertMoneyInfoVO>> expertMap = zjkExpertMoneyInfoList.stream().collect(Collectors.groupingBy(ZjkExpertMoneyInfoVO::getExpertType));
        BigDecimal feeSum = zjkExpertMoneyInfoList.stream().map(ZjkExpertMoneyInfoVO::getExpertTypeMoneyFee).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        List<ZjkMoneyAnalyseStatement> zjkMoneyAnalyseStatementList = new ArrayList<>();

        // 将 Date 转换为 Instant
        Instant instant = startTime.toInstant();

        // 将 Instant 转换为 ZonedDateTime，指定时区
        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());

        // 将 ZonedDateTime 转换为 LocalDate
        LocalDate localDate = zonedDateTime.toLocalDate();

        Date[] LastDateArray = DateUtils.getLastMonthDateRange(localDate);
        Date LastDate = LastDateArray[0];

        //上一月
        List<ZjkMoneyAnalyseStatement> statementList = zjkMoneyAnalyseStatementMapper.selectByDate(LastDate, code);
        Map<String, BigDecimal> statementMap = statementList.stream().collect(Collectors.toMap(ZjkMoneyAnalyseStatement::getExpertType, ZjkMoneyAnalyseStatement::getSumFee));
        for (String expertType : expertMap.keySet()) {
            List<ZjkExpertMoneyInfoVO> zjkExpertMoneyInfoVOS = expertMap.get(expertType);
            if (CollectionUtil.isNotEmpty(zjkExpertMoneyInfoVOS)) {
                ZjkMoneyAnalyseStatement zjkMoneyAnalyseStatement = new ZjkMoneyAnalyseStatement();
                //总费用
                BigDecimal expertTypeMoneyFee = zjkExpertMoneyInfoVOS.stream().map(ZjkExpertMoneyInfoVO::getExpertTypeMoneyFee).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                // 计算百分比
                BigDecimal percentage = expertTypeMoneyFee.divide(feeSum, RoundingMode.HALF_EVEN).multiply(new BigDecimal(100));
                BigDecimal lastYearSales = statementMap.get(expertType);

                if (lastYearSales != null && lastYearSales.compareTo(BigDecimal.ZERO) > 0) {
                    // 计算涨幅百分比
                    BigDecimal percentageChange = expertTypeMoneyFee.subtract(lastYearSales)
                        .divide(lastYearSales,2, RoundingMode.HALF_EVEN)
                        .multiply(new BigDecimal(100));
                    zjkMoneyAnalyseStatement.setTendency(percentageChange);
                } else {
                    // 如果去年的销售额为零，可以考虑设置一个默认值或处理方式
                    zjkMoneyAnalyseStatement.setTendency(BigDecimal.ZERO);
                }
                zjkMoneyAnalyseStatement.setSumFee(expertTypeMoneyFee);
                zjkMoneyAnalyseStatement.setProportion(percentage);
                zjkMoneyAnalyseStatement.setExpertType(expertType);
                zjkMoneyAnalyseStatement.setStatementId(moneyStatement.getId());
                zjkMoneyAnalyseStatementList.add(zjkMoneyAnalyseStatement);
            }
        }
        zjkMoneyAnalyseStatementMapper.insertBatch(zjkMoneyAnalyseStatementList);
        zjkMoneyCollectStatementMapper.insertBatch(zjkMoneyCollectStatements);
        zjkMoneyExpertStatementMapper.insertBatch(zjkMoneyExpertStatementList);
    }

}
