package com.ym.mec.biz.service.impl;

import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.OrganFullJobResourceNumDto;
import com.ym.mec.biz.dal.entity.CooperationOrgan;
import com.ym.mec.biz.dal.entity.FinancialExpenditure;
import com.ym.mec.biz.dal.entity.OperatingReport;
import com.ym.mec.biz.dal.entity.Organization;
import com.ym.mec.biz.dal.enums.ExpenditureTypeEnum;
import com.ym.mec.biz.service.OperatingReportService;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.util.date.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
public class OperatingReportServiceImpl extends BaseServiceImpl<Integer, OperatingReport> implements OperatingReportService {

    @Autowired
    private OperatingReportDao operatingReportDao;
    @Autowired
    private SellOrderDao sellOrderDao;
    @Autowired
    private CooperationOrganDao cooperationOrganDao;
    @Autowired
    private FinancialExpenditureDao financialExpenditureDao;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private OrganizationDao organizationDao;


    @Override
    public BaseDAO<Integer, OperatingReport> getDAO() {
        return operatingReportDao;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean statistics() {
        Date nowDate = new Date();
        Date startTime = DateUtil.getFirstDayOfMonth(DateUtil.addDays1(nowDate, -1));
        Date endTime = DateUtil.getLastTimeWithDay(DateUtil.getLastDayOfMonth(startTime));

        Map<Integer, OperatingReport> cooperationOperating = new HashMap<>();
        Map<Integer, OperatingReport> organOperating = new HashMap<>();

        //1.1 获取分部的全职资源数的分摊费用
        BigDecimal fullJobFee = new BigDecimal(sysConfigDao.findConfigValue("full_job_fee"));
        List<OrganFullJobResourceNumDto> organFullJobResources = cooperationOrganDao.getOrganFullJobResourceNum();
        for (OrganFullJobResourceNumDto organFullJobResource : organFullJobResources) {
            OperatingReport operatingReport = new OperatingReport();
            operatingReport.setOrganId(organFullJobResource.getOrganId());
            operatingReport.setDistributionAmount(new BigDecimal(organFullJobResource.getNum()).multiply(fullJobFee).divide(new BigDecimal(12), 2, BigDecimal.ROUND_HALF_UP));
            organOperating.put(organFullJobResource.getOrganId(), operatingReport);
        }
        //1.2 初始化没有全职资源数的分部
        List<Organization> organs = organizationDao.findAllOrgans();
        for (Organization organ : organs) {
            if(organOperating.containsKey(organ.getId())) continue;
            OperatingReport operatingReport = new OperatingReport();
            operatingReport.setOrganId(organ.getId());
            organOperating.put(organ.getId(), operatingReport);
        }
        //1.3 合作单位的全职资源分摊费用
        List<CooperationOrgan> allCooperationOrgan = cooperationOrganDao.getAllCooperationOrgan();
        for (CooperationOrgan cooperationOrgan : allCooperationOrgan) {
            OperatingReport operatingReport = new OperatingReport();
            operatingReport.setOrganId(cooperationOrgan.getOrganId());
            operatingReport.setCooperationOrganId(cooperationOrgan.getId());
            BigDecimal distributionAmount = cooperationOrgan.getFullJobResource().equals(1) ? fullJobFee.divide(new BigDecimal(12), 2, BigDecimal.ROUND_HALF_UP) : BigDecimal.ZERO;
            operatingReport.setDistributionAmount(distributionAmount);
            cooperationOperating.put(cooperationOrgan.getId(), operatingReport);
        }

        //2、获取支出费用
        List<FinancialExpenditure> cooperationExpenditures = financialExpenditureDao.getCooperationExpenditure(startTime, endTime);
        for (FinancialExpenditure cooperationExpenditure : cooperationExpenditures) {
            OperatingReport organOperatingReport = new OperatingReport();
            if (organOperating.containsKey(cooperationExpenditure.getOrganId())) {
                organOperatingReport = organOperating.get(cooperationExpenditure.getOrganId());
            }

            OperatingReport cooperationOperatingReport = new OperatingReport();
            if (cooperationExpenditure.getCooperationOrganId() != null && cooperationOperating.containsKey(cooperationExpenditure.getCooperationOrganId())) {
                cooperationOperatingReport = cooperationOperating.get(cooperationExpenditure.getCooperationOrganId());
            }

            organOperatingReport.setOrganId(cooperationExpenditure.getOrganId());
            cooperationOperatingReport.setOrganId(cooperationExpenditure.getOrganId());
            cooperationOperatingReport.setCooperationOrganId(cooperationExpenditure.getCooperationOrganId());
            if (cooperationExpenditure.getType().equals(ExpenditureTypeEnum.FIXED)) {
                organOperatingReport.setExpensesAmount(organOperatingReport.getExpensesAmount().add(cooperationExpenditure.getAmount()));
                cooperationOperatingReport.setExpensesAmount(cooperationExpenditure.getAmount());
            } else if (cooperationExpenditure.getType().equals(ExpenditureTypeEnum.VARIABLE)) {
                organOperatingReport.setVariableCost(organOperatingReport.getVariableCost().add(cooperationExpenditure.getAmount()));
                cooperationOperatingReport.setVariableCost(cooperationExpenditure.getAmount());
            } else if (cooperationExpenditure.getType().equals(ExpenditureTypeEnum.REFUND)) {
                organOperatingReport.setRefundAmount(organOperatingReport.getRefundAmount().add(cooperationExpenditure.getAmount()));
                cooperationOperatingReport.setRefundAmount(cooperationExpenditure.getAmount());
            }
            organOperating.put(cooperationExpenditure.getOrganId(), organOperatingReport);

            if (cooperationExpenditure.getCooperationOrganId() != null) {
                cooperationOperating.put(cooperationExpenditure.getCooperationOrganId(), cooperationOperatingReport);
            }
        }

        //3.1、乐团销售订单的统计
        List<OperatingReport> reports = sellOrderDao.getMusicGroupMonthReport(startTime, endTime);
        //乐团订单总收入的统计
        reports.addAll(sellOrderDao.getMusicGroupIncome(startTime, endTime));
        //3.2、VIP、网管课订单的统计（关联学生注册取一条记录）
        reports.addAll(sellOrderDao.getMusicVipPracticeMonthReport(startTime, endTime));
        //3.3、外部添加订单销售
        reports.addAll(sellOrderDao.getOutOrderMonthReport(startTime, endTime));
        //外部添加订单销售总收入
        reports.addAll(sellOrderDao.getOutOrderIncome(startTime, endTime));
        //3.4、乐器维修
        reports.addAll(sellOrderDao.getRepairGoodsSellGroupMonthReport(startTime, endTime));
        reports.addAll(sellOrderDao.getRepairGoodsSellGroupIncome(startTime, endTime));
        //3.5、商品销售
        reports.addAll(sellOrderDao.getGoodsSellGroupMonthReport(startTime, endTime));
        //3.6、零星支付充值
        reports.addAll(sellOrderDao.getRechargeMonthReport(startTime, endTime));
        //3.7、零星收费（不是充值部分的）
        reports.addAll(sellOrderDao.getSporadicMonthReport(startTime, endTime));
        //3.8 声部更换的收入
        reports.addAll(sellOrderDao.getSubjectChangeMonthReport(startTime, endTime));
        reports.addAll(sellOrderDao.getSubjectChangeGroupIncome(startTime, endTime));
        //3.9 退货部分的统计
        reports.addAll(sellOrderDao.getRefundIncome(startTime, endTime));

        updateFee(organOperating, cooperationOperating, reports);

//        Map<String, Object> params = new HashMap<>();
//        params.put("startTime", startTime);
//        params.put("endTime", endTime);
//        organOperating.forEach((organId, operatingReport) -> {
//            operatingReport.setMonth(startTime);
//            operatingReport.setCreateTime(nowDate);
//            updateReport(operatingReport, params);
//        });
//        cooperationOperating.forEach((organId, operatingReport) -> {
//            operatingReport.setMonth(startTime);
//            operatingReport.setCreateTime(nowDate);
//            updateReport(operatingReport, params);
//        });
        return true;
    }

    /**
     * 计算总收入
     *
     * @param organOperating
     * @param cooperationOperating
     * @param reports
     */
    private void updateFee(Map<Integer, OperatingReport> organOperating, Map<Integer, OperatingReport> cooperationOperating, List<OperatingReport> reports) {
        for (OperatingReport report : reports) {
            OperatingReport organOperatingReport = new OperatingReport();
            if (organOperating.containsKey(report.getOrganId())) {
                organOperatingReport = organOperating.get(report.getOrganId());
            }

            OperatingReport cooperationOperatingReport = new OperatingReport();
            if (report.getCooperationOrganId() != null && cooperationOperating.containsKey(report.getCooperationOrganId())) {
                cooperationOperatingReport = cooperationOperating.get(report.getCooperationOrganId());
            }
            organOperatingReport.setOrganId(report.getOrganId());
            cooperationOperatingReport.setOrganId(report.getOrganId());
            cooperationOperatingReport.setCooperationOrganId(report.getCooperationOrganId());

            if (report.getSellAmount() == null) {
                report.setSellAmount(BigDecimal.ZERO);
                report.setSellCost(BigDecimal.ZERO);
            }
            if (report.getIncomeTotal() == null) {
                report.setIncomeTotal(BigDecimal.ZERO);
            }
            if (report.getOtherIncome() == null) {
                report.setOtherIncome(BigDecimal.ZERO);
            }

            //总收入
            organOperatingReport.setIncomeTotal(organOperatingReport.getIncomeTotal().add(report.getIncomeTotal()));
            cooperationOperatingReport.setIncomeTotal(cooperationOperatingReport.getIncomeTotal().add(report.getIncomeTotal()));

            //销售收入
            organOperatingReport.setSellAmount(organOperatingReport.getSellAmount().add(report.getSellAmount()));
            organOperatingReport.setSellCost(organOperatingReport.getSellCost().add(report.getSellCost()));
            cooperationOperatingReport.setSellAmount(cooperationOperatingReport.getSellAmount().add(report.getSellAmount()));
            cooperationOperatingReport.setSellCost(cooperationOperatingReport.getSellCost().add(report.getSellCost()));

            //其他收入
            organOperatingReport.setOtherIncome(organOperatingReport.getOtherIncome().add(report.getOtherIncome()));
            cooperationOperatingReport.setOtherIncome(cooperationOperatingReport.getOtherIncome().add(report.getOtherIncome()));

            organOperating.put(report.getOrganId(), organOperatingReport);
            if (report.getCooperationOrganId() != null) {
                cooperationOperating.put(report.getCooperationOrganId(), cooperationOperatingReport);
            }
        }
        Date nowDate = new Date();
        Date startTime = DateUtil.getFirstDayOfMonth(DateUtil.addDays1(nowDate, -1));
        Date endTime = DateUtil.getLastTimeWithDay(DateUtil.getLastDayOfMonth(startTime));
        Map<String, Object> params = new HashMap<>();
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        organOperating.forEach((organId, operatingReport) -> {
            operatingReport.setMonth(startTime);
            operatingReport.setCreateTime(nowDate);
            updateReport(operatingReport, params);
        });
        cooperationOperating.forEach((organId, operatingReport) -> {
            operatingReport.setMonth(startTime);
            operatingReport.setCreateTime(nowDate);
            updateReport(operatingReport, params);
        });
    }

    private void updateReport(OperatingReport operatingReport, Map<String, Object> params) {
        //收入合计：销售收入+服务收入-业务退费
        BigDecimal serviceTotal = operatingReport.getIncomeTotal().subtract(operatingReport.getSellAmount()).subtract(operatingReport.getOtherIncome());
        operatingReport.setServiceAmount(serviceTotal);
        BigDecimal incomeTotal = operatingReport.getIncomeTotal().subtract(operatingReport.getRefundAmount());
        operatingReport.setIncomeTotal(incomeTotal);
        //成本费用合计：销售成本+固定支出+变动支出+分摊费用
        BigDecimal costAmount = operatingReport.getSellCost().add(operatingReport.getExpensesAmount()).add(operatingReport.getVariableCost()).add(operatingReport.getDistributionAmount());
        operatingReport.setCostAmount(costAmount);
        //利润：收入合计-成本费用合计
        operatingReport.setProfit(incomeTotal.subtract(costAmount));
        params.put("organId", operatingReport.getOrganId());
        params.put("cooperationOrganId", operatingReport.getCooperationOrganId());
        OperatingReport hasReport = operatingReportDao.getReport(params);
        if (hasReport == null) {
            operatingReportDao.insert(operatingReport);
        } else {
            operatingReport.setId(hasReport.getId());
            operatingReportDao.update(operatingReport);
        }
    }
}
