package cn.ezhizao.project.business.deduct.controller;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import cn.ezhizao.common.utils.DateUtils;
import cn.ezhizao.project.business.company.domain.BizCompany;
import cn.ezhizao.project.business.company.service.IBizCompanyService;
import cn.ezhizao.project.business.deposit.domain.BizDeposit;
import cn.ezhizao.project.business.deposit.service.IBizDepositService;
import cn.ezhizao.project.business.entrust.domain.BizEntrust;
import cn.ezhizao.project.business.entrust.service.IBizEntrustService;
import cn.ezhizao.project.business.entrustOrder.domain.BizEntrustOrder;
import cn.ezhizao.project.business.entrustOrder.service.IBizEntrustOrderService;
import cn.ezhizao.project.business.entrustPrice.domain.BizEntrustPrice;
import cn.ezhizao.project.business.entrustPrice.service.IBizEntrustPriceService;
import cn.ezhizao.project.business.housingFund.domain.BizHousingFundConfirmDetail;
import cn.ezhizao.project.business.housingFund.service.IBizHousingFundConfirmDetailService;
import cn.ezhizao.project.business.keepAccounts.domain.BizFinancialKeepAccountDetail;
import cn.ezhizao.project.business.keepAccounts.service.IBizFinancialKeepAccountDetailService;
import cn.ezhizao.project.business.socialSecurity.domain.BizSocialSecurityConfirmDetail;
import cn.ezhizao.project.business.socialSecurity.service.IBizSocialSecurityConfirmDetailService;
import cn.ezhizao.project.business.statementAccount.domain.BizStatementAccount;
import cn.ezhizao.project.business.statementAccount.domain.BizStatementAccountLoop;
import cn.ezhizao.project.business.statementAccount.domain.BizStatementAccountOnce;
import cn.ezhizao.project.business.statementAccount.service.IBizStatementAccountLoopService;
import cn.ezhizao.project.business.statementAccount.service.IBizStatementAccountOnceService;
import cn.ezhizao.project.business.statementAccount.service.IBizStatementAccountService;
import cn.ezhizao.project.business.workOrder.domain.BizWorkOrder;
import cn.ezhizao.project.business.workOrder.domain.BizWorkOrderRecord;
import cn.ezhizao.project.business.workOrder.service.IBizWorkOrderRecordService;
import cn.ezhizao.project.business.workOrder.service.IBizWorkOrderService;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
import cn.ezhizao.project.business.deduct.domain.BizDeduct;
import cn.ezhizao.project.business.deduct.service.IBizDeductService;
import cn.ezhizao.framework.web.controller.BaseController;
import cn.ezhizao.framework.web.domain.AjaxResult;
import cn.ezhizao.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.web.page.TableDataInfo;

/**
 * 扣款记录Controller
 *
 * @author ruoyi
 * @date 2023-11-13
 */
@RestController
@RequestMapping("/business/deduct")
public class BizDeductController extends BaseController {
    @Resource
    private IBizDeductService bizDeductService;
    @Resource
    private IBizStatementAccountService statementAccountService;
    @Resource
    private IBizStatementAccountLoopService statementAccountLoopService;
    @Resource
    private IBizStatementAccountOnceService statementAccountOnceService;
    @Resource
    private IBizEntrustOrderService bizEntrustOrderService;
    @Resource
    private IBizEntrustService entrustService;
    @Resource
    private IBizFinancialKeepAccountDetailService keepAccountDetailService;
    @Resource
    private IBizCompanyService companyService;
    @Resource
    private IBizWorkOrderService workOrderService;
    @Resource
    private IBizWorkOrderRecordService workOrderRecordService;
    @Resource
    private IBizEntrustPriceService entrustPriceService;
    @Resource
    private IBizHousingFundConfirmDetailService bizHousingFundConfirmDetailService;
    @Resource
    private IBizSocialSecurityConfirmDetailService bizSocialSecurityConfirmDetailService;
    @Resource
    private IBizDepositService depositService;

    /**
     * 查询扣款记录列表
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:list')")
    @GetMapping("/list")
    public TableDataInfo list(BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizDeduct);
        startPage();
        startOrderBy();
        List<BizDeduct> list = bizDeductService.getList(bizDeduct);
        return getDataTable(list);
    }

    @PreAuthorize("@ss.hasPermi('business:deduct:list')")
    @GetMapping("/getEntrustOrder/{id}")
    public AjaxResult getEntrustOrder(@PathVariable("id") Long id) throws NoSuchFieldException, IllegalAccessException {
        BizEntrustOrder bizEntrustOrder = bizEntrustOrderService.getById(id);
        return success(bizEntrustOrder);
    }

    /**
     * 导出扣款记录列表
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:export')")
    @Log(title = "扣款记录", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        setTenantId(bizDeduct);
//        startPage();
        startOrderBy();
        List<BizDeduct> list = bizDeductService.getList(bizDeduct);
        list.forEach(item -> {
            item.setContactMsg(item.getYear()+"年"+item.getMonth()+"月");
            switch (item.getStatus()){
                case 0:
                    item.setStatusName("已提交");
                    break;
                case 1:
                    item.setStatusName("已确认");
                    break;
                case 2:
                    item.setStatusName("已扣款");
                    break;
                case 4:
                    item.setStatusName("已驳回");
                    break;
            }

        });
        ExcelUtil<BizDeduct> util = new ExcelUtil<BizDeduct>(BizDeduct.class);
        util.exportExcel(response, list, "扣款记录数据");
    }

    /**
     * 获取扣款记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:info')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        BizDeduct conditions = new BizDeduct();
        conditions.setId(id);
        BizDeduct deduct = bizDeductService.getList(conditions).stream().findFirst().orElse(null);
        if (deduct != null) {
            BizEntrustOrder order = bizEntrustOrderService.getById(deduct.getEntrustOrderId());
            if(order==null){
                return error("未查到该委托单号，请检查是否存在，或联系管理员。");
            }
            deduct.setEntrustOrderStatus(order.getStatus());
            BizStatementAccount statementAccountCondition = new BizStatementAccount();
            statementAccountCondition.setDeductId(id);
            List<BizStatementAccount> accounts = statementAccountService.getList(statementAccountCondition);
            BizStatementAccountLoop loopCondition = new BizStatementAccountLoop();
            loopCondition.setDeductId(id);
            List<BizStatementAccountLoop> loops = statementAccountLoopService.getList(loopCondition);
            BizStatementAccountOnce onceCondition = new BizStatementAccountOnce();
            onceCondition.setDeductId(id);
            List<BizStatementAccountOnce> once = statementAccountOnceService.getList(onceCondition);
            deduct.setCollect(accounts);
            deduct.setOnceList(once);
            deduct.setLoopList(loops);
        }
        return success(deduct);
    }


    /**
     * 获取扣款记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:add')")
    @GetMapping(value = "/gen")
    public AjaxResult genInfo(BizDeduct conditions) {
        // 获取主表
        BizDeduct bizDeduct = new BizDeduct();
        bizDeduct.setEntrustOrderId(conditions.getEntrustOrderId());
        bizDeduct.setMonth(DateTime.of(conditions.getStartMonth()).toString("MM"));
        bizDeduct.setYear(DateTime.of(conditions.getStartMonth()).toString("yyyy"));
        bizDeduct.setStartMonth(conditions.getStartMonth());
        bizDeduct.setEndMonth(conditions.getEndMonth());
        bizDeduct.setStatementDate(DateTime.now().toJdkDate());

        BizEntrustOrder entrustCondition = new BizEntrustOrder();
        entrustCondition.setId(conditions.getEntrustOrderId());
        BizEntrustOrder bizEntrustOrder = bizEntrustOrderService.getList(entrustCondition).stream().findFirst().orElse(null);
        if (bizEntrustOrder == null) {
            return error("委托单不存在");
        }
        // 结算订单号
        bizDeduct.setFormNo(bizEntrustOrder.getFormNo());
        bizDeduct.setTenantId(bizEntrustOrder.getTenantId());
        bizDeduct.setFromTenantId(bizEntrustOrder.getFromTenantId());
        bizDeduct.setContactCompany(bizEntrustOrder.getContactCompany());
        bizDeduct.setSigningSubject(bizEntrustOrder.getSigningSubject());
        bizDeduct.setStartMonth(conditions.getStartMonth());
        bizDeduct.setEndMonth(conditions.getEndMonth());
        // 上期余额
        BizDeposit totalCondition = new BizDeposit();
        totalCondition.setEntrustOrderId(bizEntrustOrder.getId());
        BigDecimal totalRemain = depositService.getTotalRemain(totalCondition);
        totalRemain = totalRemain == null ? BigDecimal.ZERO : totalRemain;
        BigDecimal donateRemain = depositService.getDonateRemain(totalCondition);
        donateRemain = donateRemain == null ? BigDecimal.ZERO : donateRemain;
        bizDeduct.setPrevRemainAmount(totalRemain.add(donateRemain));

        // 获取循环从表
        BizEntrust entrustLoopCondition = new BizEntrust();
        entrustLoopCondition.setToTenantId(bizEntrustOrder.getTenantId());
        entrustLoopCondition.setFromTenantId(bizEntrustOrder.getFromTenantId());
        entrustLoopCondition.setWorkMonthFrom(DateTime.of(conditions.getStartMonth()).toSqlDate());
        entrustLoopCondition.setWorkMonthTo(DateTime.of(conditions.getEndMonth()).toSqlDate());
        entrustLoopCondition.setType(1);
        List<BizEntrust> loopEntrust = entrustService.getList(entrustLoopCondition);
        List<BizStatementAccountLoop> loops = new ArrayList<>();
        BizFinancialKeepAccountDetail keepAccountCondition = new BizFinancialKeepAccountDetail();
        keepAccountCondition.setStartMonth(DateTime.of(conditions.getStartMonth()).toSqlDate());
        keepAccountCondition.setEndMonth(DateTime.of(conditions.getEndMonth()).toSqlDate());
        List<BizFinancialKeepAccountDetail> keepAccountDetails = keepAccountDetailService.getList(keepAccountCondition);
        BizHousingFundConfirmDetail housingFundCondition = new BizHousingFundConfirmDetail();
        housingFundCondition.setStartMonth(DateTime.of(conditions.getStartMonth()).toSqlDate());
        housingFundCondition.setEndMonth(DateTime.of(conditions.getEndMonth()).toSqlDate());
        List<BizHousingFundConfirmDetail> housingFundConfirmDetails = bizHousingFundConfirmDetailService.getListByBean(housingFundCondition);
        BizSocialSecurityConfirmDetail socialSecurityConditions = new BizSocialSecurityConfirmDetail();
        socialSecurityConditions.setStartMonth(DateTime.of(conditions.getStartMonth()).toSqlDate());
        socialSecurityConditions.setEndMonth(DateTime.of(conditions.getEndMonth()).toSqlDate());
        List<BizSocialSecurityConfirmDetail> socialSecurityConfirmDetails = bizSocialSecurityConfirmDetailService.getListByBean(socialSecurityConditions);
        BizCompany companyCondition = new BizCompany();
        companyCondition.setIds(loopEntrust.stream().map(BizEntrust::getCompanyId).collect(Collectors.toList()));
        List<BizCompany> companies = null;
        if (loopEntrust.size() > 0) {
            companies = companyService.getList(companyCondition);
        } else {
            companies = new ArrayList<>();
        }
        List<String> months = loopEntrust.stream().map(v -> DateTime.of(v.getWorkMonth()).toString("yyyy-MM-dd")).distinct().sorted().collect(Collectors.toList());
        List<BizCompany> finalCompanies = companies;
        months.forEach(l -> {
            List<BizEntrust> monthEntrust = loopEntrust.stream().filter(v -> DateTime.of(v.getWorkMonth()).toString("yyyy-MM-dd").equals(l)).collect(Collectors.toList());
            finalCompanies.stream().filter(v -> monthEntrust.stream().anyMatch(e -> e.getCompanyId().equals(v.getId()))).forEach(v -> {
                BizStatementAccountLoop item = new BizStatementAccountLoop();
                item.setEntrustOrderId(bizDeduct.getEntrustOrderId());
                item.setSocialCreditCode(v.getSocialCreditCode());
                item.setCompanyId(v.getId());
                item.setCompanyName(v.getName());
                item.setProvince(v.getProvince());
                item.setCity(v.getCity());
                item.setDistrict(v.getDistrict());
                item.setWorkMonth(DateTime.of(l, "yyyy-MM-dd").toSqlDate());
                BizFinancialKeepAccountDetail keepAccountDetail = keepAccountDetails.stream().filter(e -> e.getCompanyId().equals(v.getId())).findFirst().orElse(null);
                item.setCumulativeIncome(keepAccountDetail != null ? keepAccountDetail.getCurrentYearIncome() : null);
                item.setQuotaAmount(v.getQuotaAmount());
                item.setCollectionMethod(v.getCollectionMethod());
                item.setTaxType(v.getTaxType());
                item.setIsTax(monthEntrust.stream().anyMatch(e -> e.getCompanyId().equals(v.getId()) && e.getTaskTypeId().equals(1L)) ? 1 : 0);
                item.setIsHousingFund(monthEntrust.stream().anyMatch(e -> e.getCompanyId().equals(v.getId()) && e.getTaskTypeId().equals(3L)) ? 1 : 0);
                item.setIsSocialSecurity(monthEntrust.stream().anyMatch(e -> e.getCompanyId().equals(v.getId()) && e.getTaskTypeId().equals(2L)) ? 1 : 0);
                item.setActuallyAnnualIncome(getAnnualIncome(keepAccountDetail != null ? keepAccountDetail.getCurrentYearIncome() : null));
                BizSocialSecurityConfirmDetail socialSecurityConfirmDetail = socialSecurityConfirmDetails.stream().filter(e -> e.getCompanyId().equals(item.getCompanyId())).findFirst().orElse(null);
                item.setChangedSocialSecurity(socialSecurityConfirmDetail == null ? 0 : socialSecurityConfirmDetail.getIsChanged());

                BizHousingFundConfirmDetail housingFundConfirmDetail = housingFundConfirmDetails.stream().filter(e -> e.getCompanyId().equals(item.getCompanyId())).findFirst().orElse(null);
                item.setChangedHousingFund(housingFundConfirmDetail == null ? 0 : housingFundConfirmDetail.getIsChanged());
                item.setAnnualIncome(v.getAnnualIncome());
                loops.add(item);
            });
        });

        // 获取单次从表
        BizEntrust entrustOnceCondition = new BizEntrust();
        entrustOnceCondition.setToTenantId(bizEntrustOrder.getTenantId());
        entrustOnceCondition.setFromTenantId(bizEntrustOrder.getFromTenantId());
        entrustOnceCondition.setType(2);
        List<BizEntrust> onceEntrust = entrustService.getList(entrustOnceCondition);
        List<BizStatementAccountOnce> onceList = new ArrayList<>();

        companyCondition = new BizCompany();
        companyCondition.setIds(onceEntrust.stream().map(BizEntrust::getCompanyId).collect(Collectors.toList()));
        companies = companyService.getList(companyCondition);

        BizWorkOrder workOrderCondition = new BizWorkOrder();
        workOrderCondition.setIds(onceEntrust.stream().map(BizEntrust::getWorkOrderId).collect(Collectors.toList()));
        List<BizWorkOrder> workOrders = workOrderService.getList(workOrderCondition);

        BizWorkOrderRecord recordCondition = new BizWorkOrderRecord();
        recordCondition.setWorkOrderIds(workOrders.stream().map(BizWorkOrder::getId).collect(Collectors.toList()));
        List<BizWorkOrderRecord> records = workOrderRecordService.getList(recordCondition);
        onceEntrust.forEach(l -> {
            BizWorkOrderRecord record = records.stream().filter(v -> v.getWorkOrderId().equals(l.getWorkOrderId()) && v.getFromId().equals(0L) && v.getStatus().equals(3) && v.getCreateTime().compareTo(conditions.getStartMonth()) >= 0 && v.getCreateTime().compareTo(DateUtil.endOfMonth(conditions.getEndMonth())) <= 0).findFirst().orElse(null);
            if (record != null) {
                BizStatementAccountOnce item = new BizStatementAccountOnce();
                item.setEntrustOrderId(bizDeduct.getEntrustOrderId());
                item.setEntrustDate(l.getCreateTime());
                item.setFinishedDate(record.getCreateTime());
                item.setWorkOrderId(l.getWorkOrderId());
                item.setCompanyId(l.getCompanyId());
                item.setCompanyName(l.getCompanyName());
                item.setTaskTypeName(l.getTaskTypeName());
                item.setTaskTypeDetailName(l.getTaskTypeDetailName());
                BizWorkOrder workOrder = workOrders.stream().filter(v -> v.getId().equals(l.getWorkOrderId())).findFirst().orElse(null);
                if (workOrder != null) {
                    item.setDescription(workOrder.getRemark());
                    item.setProvince(workOrder.getProvince());
                    item.setProvinceCode(workOrder.getProvinceCode());
                    item.setCity(workOrder.getCity());
                    item.setCityCode(workOrder.getCityCode());
                    item.setDistrict(workOrder.getDistrict());
                    item.setDistrictCode(workOrder.getDistrictCode());
                }
                onceList.add(item);
            }
        });

        // 获取汇总
        List<BizStatementAccount> accounts;
        accounts = getStatementAccount(onceList, loops, bizDeduct);
        bizDeduct.setCollect(accounts);
        bizDeduct.setLoopList(loops);
        bizDeduct.setOnceList(onceList);

        // 本期消耗
        BigDecimal deduct = BigDecimal.valueOf(accounts.stream().mapToDouble(v -> v.getActuallyAmount().doubleValue()).sum()).setScale(2, RoundingMode.HALF_UP);
        bizDeduct.setAmount(deduct);
        // 本期余额
        bizDeduct.setRemainAmount(bizDeduct.getPrevRemainAmount().subtract(deduct));
        return success(bizDeduct);
    }

    private List<BizStatementAccount> getStatementAccount(List<BizStatementAccountOnce> onceList, List<BizStatementAccountLoop> loops, BizDeduct bizDeduct) {
        List<BizStatementAccount> accounts = new ArrayList<>();
        BizEntrustPrice priceCondition = new BizEntrustPrice();
//        priceCondition.setFromTenantId(bizDeduct.getFromTenantId());
        priceCondition.setToTenantId(bizDeduct.getTenantId());
        List<BizEntrustPrice> prices = entrustPriceService.getList(priceCondition);
        List<BizEntrustPrice> oncePrices = entrustPriceService.query().gt("task_type_id", 4).list();
        if (loops.stream().anyMatch(v -> v.getIsTax().equals(1))) {
            // 代理记账
            addStatementAccountByAnnualIncome(loops.stream().filter(v -> v.getIsTax().equals(1)).collect(Collectors.toList()), accounts, bizDeduct, prices);
        }
        if (loops.stream().anyMatch(v -> v.getIsSocialSecurity().equals(1))) {
            // 社保代缴
            addSecurityStatementAccountByChanged(loops.stream().filter(v -> v.getIsSocialSecurity().equals(1)).collect(Collectors.toList()), accounts, bizDeduct, prices);
        }
        if (loops.stream().anyMatch(v -> v.getIsSocialSecurity().equals(1))) {
            // 公积金代缴
            addHousingStatementAccountByChanged(loops.stream().filter(v -> v.getIsHousingFund().equals(1)).collect(Collectors.toList()), accounts, bizDeduct, prices);
        }
        // 代办任务
        addAffairStatementAccount(onceList, accounts, bizDeduct, oncePrices);

        return accounts;
    }

    private void addAffairStatementAccount(List<BizStatementAccountOnce> onceList, List<BizStatementAccount> accounts, BizDeduct bizDeduct, List<BizEntrustPrice> prices) {
        // 给个默认单价
        onceList.forEach(v -> {
            BizEntrustPrice price = prices.stream().filter(l -> l.getTaskTypeId().equals(v.getTaskTypeId()) && l.getTaskTypeDetailId().equals(v.getTaskTypeDetailId()) && l.getProvince().equals(v.getProvince()) && l.getCity().equals(v.getCity()) && l.getDistrict().equals(v.getDistrict())).findFirst().orElse(null);
            v.setAmount(price != null ? price.getPrice() : null);
        });
        BizStatementAccount once = new BizStatementAccount();
        once.setTaskType("工商代办");
        BigDecimal amount = BigDecimal.valueOf(onceList.stream().mapToDouble(v -> v.getAmount() == null ? 0.0 : v.getAmount().doubleValue()).sum());
        once.setYear(bizDeduct.getYear());
        once.setMonth(bizDeduct.getMonth());
        once.setActuallyAmount(amount);
        once.setAmount(amount);
        accounts.add(once);
    }

    private void addSecurityStatementAccountByChanged(List<BizStatementAccountLoop> collect, List<BizStatementAccount> accounts, BizDeduct bizDeduct, List<BizEntrustPrice> prices) {
        // 无变化
        List<BizStatementAccountLoop> unchanged = collect.stream().filter(v -> v.getChangedSocialSecurity().equals(0)).collect(Collectors.toList());
        BizStatementAccount first = new BizStatementAccount();
        first.setHaveChanged(0);
        first.setMonth(bizDeduct.getMonth());
        first.setYear(bizDeduct.getYear());
        first.setTaskType("社保代缴");
        first.setCompanyNum(unchanged.size());
        BizEntrustPrice price = prices.stream().filter(v -> v.getIsChanged().equals(0) && v.getTaskTypeId().equals(2L)).findFirst().orElse(null);
        first.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        first.setAmount(first.getPrice().multiply(BigDecimal.valueOf(first.getCompanyNum())));
        first.setActuallyAmount(first.getAmount());
        accounts.add(first);
        // 有变化
        List<BizStatementAccountLoop> changed = collect.stream().filter(v -> v.getChangedSocialSecurity().equals(1)).collect(Collectors.toList());
        BizStatementAccount second = new BizStatementAccount();
        second.setHaveChanged(1);
        second.setMonth(bizDeduct.getMonth());
        second.setYear(bizDeduct.getYear());
        second.setTaskType("社保代缴");
        second.setCompanyNum(changed.size());
        price = prices.stream().filter(v -> v.getIsChanged().equals(1) && v.getTaskTypeId().equals(2L)).findFirst().orElse(null);
        second.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        second.setAmount(second.getPrice().multiply(BigDecimal.valueOf(second.getCompanyNum())));
        second.setActuallyAmount(second.getAmount());
        accounts.add(second);
    }

    private void addHousingStatementAccountByChanged(List<BizStatementAccountLoop> collect, List<BizStatementAccount> accounts, BizDeduct bizDeduct, List<BizEntrustPrice> prices) {
        // 无变化
        List<BizStatementAccountLoop> unchanged = collect.stream().filter(v -> v.getChangedSocialSecurity().equals(0)).collect(Collectors.toList());
        BizStatementAccount first = new BizStatementAccount();
        first.setHaveChanged(0);
        first.setMonth(bizDeduct.getMonth());
        first.setYear(bizDeduct.getYear());
        first.setTaskType("公积金代缴");
        first.setCompanyNum(unchanged.size());
        BizEntrustPrice price = prices.stream().filter(v -> v.getIsChanged().equals(0) && v.getTaskTypeId().equals(3L)).findFirst().orElse(null);
        first.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        first.setAmount(first.getPrice().multiply(BigDecimal.valueOf(first.getCompanyNum())));
        first.setActuallyAmount(first.getAmount());
        accounts.add(first);
        // 有变化
        List<BizStatementAccountLoop> changed = collect.stream().filter(v -> v.getChangedSocialSecurity().equals(1)).collect(Collectors.toList());
        BizStatementAccount second = new BizStatementAccount();
        second.setHaveChanged(1);
        second.setMonth(bizDeduct.getMonth());
        second.setYear(bizDeduct.getYear());
        second.setTaskType("公积金代缴");
        second.setCompanyNum(changed.size());
        price = prices.stream().filter(v -> v.getIsChanged().equals(1) && v.getTaskTypeId().equals(3L)).findFirst().orElse(null);
        second.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        second.setAmount(second.getPrice().multiply(BigDecimal.valueOf(second.getCompanyNum())));
        second.setActuallyAmount(second.getAmount());
        accounts.add(second);
    }

    private void addStatementAccountByAnnualIncome(List<BizStatementAccountLoop> loop, List<BizStatementAccount> accounts, BizDeduct deduct, List<BizEntrustPrice> prices) {
        // 年收入0
        String annualIncome = "0";
        List<BizStatementAccountLoop> zero = loop.stream().filter(v -> v.getActuallyAnnualIncome().equals(annualIncome)).collect(Collectors.toList());
        BizStatementAccount first = new BizStatementAccount();
        first.setTaskType("代理记账");
        first.setAnnualIncome(annualIncome);
        first.setCompanyNum(zero.size());
        BizEntrustPrice price = prices.stream().filter(v -> v.getAnnualIncome().equals(annualIncome)).findFirst().orElse(null);
        first.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        first.setAmount(first.getPrice().multiply(BigDecimal.valueOf(first.getCompanyNum())));
        first.setActuallyAmount(first.getAmount());
        first.setYear(deduct.getYear());
        first.setMonth(deduct.getMonth());
        accounts.add(first);
        // 年收入0-200万元
        String secondAnnualIncome = "0~200万元";
        List<BizStatementAccountLoop> two = loop.stream().filter(v -> v.getActuallyAnnualIncome().equals(secondAnnualIncome)).collect(Collectors.toList());
        BizStatementAccount second = new BizStatementAccount();
        second.setTaskType("代理记账");
        second.setAnnualIncome(secondAnnualIncome);
        second.setCompanyNum(two.size());
        price = prices.stream().filter(v -> v.getAnnualIncome().equals(secondAnnualIncome)).findFirst().orElse(null);
        second.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        second.setAmount(second.getPrice().multiply(BigDecimal.valueOf(second.getCompanyNum())));
        second.setActuallyAmount(second.getAmount());
        second.setYear(deduct.getYear());
        second.setMonth(deduct.getMonth());
        accounts.add(second);
        // 年收入200-500万元
        String thirdAnnualIncome = "200~500万元";
        List<BizStatementAccountLoop> five = loop.stream().filter(v -> v.getActuallyAnnualIncome().equals(thirdAnnualIncome)).collect(Collectors.toList());
        BizStatementAccount third = new BizStatementAccount();
        third.setTaskType("代理记账");
        third.setAnnualIncome(thirdAnnualIncome);
        third.setCompanyNum(five.size());
        price = prices.stream().filter(v -> v.getAnnualIncome().equals(thirdAnnualIncome)).findFirst().orElse(null);
        third.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        third.setAmount(third.getPrice().multiply(BigDecimal.valueOf(third.getCompanyNum())));
        third.setActuallyAmount(third.getAmount());
        third.setYear(deduct.getYear());
        third.setMonth(deduct.getMonth());
        accounts.add(third);
        // 年收入500-1000万元
        String fourthAnnualIncome = "500~1000万元";
        List<BizStatementAccountLoop> ten = loop.stream().filter(v -> v.getActuallyAnnualIncome().equals(fourthAnnualIncome)).collect(Collectors.toList());
        BizStatementAccount fourth = new BizStatementAccount();
        fourth.setTaskType("代理记账");
        fourth.setAnnualIncome(fourthAnnualIncome);
        fourth.setCompanyNum(ten.size());
        price = prices.stream().filter(v -> v.getAnnualIncome().equals(fourthAnnualIncome)).findFirst().orElse(null);
        fourth.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        fourth.setAmount(fourth.getPrice().multiply(BigDecimal.valueOf(fourth.getCompanyNum())));
        fourth.setActuallyAmount(fourth.getAmount());
        fourth.setYear(deduct.getYear());
        fourth.setMonth(deduct.getMonth());
        accounts.add(fourth);
        // 年收入1000万元以上
        String fifthAnnualIncome = "1000万元以上";
        List<BizStatementAccountLoop> more = loop.stream().filter(v -> v.getActuallyAnnualIncome().equals(fifthAnnualIncome)).collect(Collectors.toList());
        BizStatementAccount fifth = new BizStatementAccount();
        fifth.setTaskType("代理记账");
        fifth.setAnnualIncome(fifthAnnualIncome);
        fifth.setCompanyNum(more.size());
        price = prices.stream().filter(v -> v.getAnnualIncome().equals(fifthAnnualIncome)).findFirst().orElse(null);
        fifth.setPrice(price != null ? price.getPrice() : BigDecimal.ZERO);
        fifth.setAmount(fifth.getPrice().multiply(BigDecimal.valueOf(fifth.getCompanyNum())));
        fifth.setActuallyAmount(fifth.getAmount());
        fifth.setYear(deduct.getYear());
        fifth.setMonth(deduct.getMonth());
        accounts.add(fifth);
        // 年收入 -
    }

    private String getAnnualIncome(BigDecimal currentYearIncome) {
        if (currentYearIncome == null || currentYearIncome.compareTo(BigDecimal.ZERO) == 0) {
            return "0";
        } else if (currentYearIncome.compareTo(BigDecimal.ZERO) > 0 && currentYearIncome.compareTo(BigDecimal.valueOf(2000000)) <= 0) {
            return "0~200万元";
        } else if (currentYearIncome.compareTo(BigDecimal.valueOf(2000000)) > 0 && currentYearIncome.compareTo(BigDecimal.valueOf(5000000)) <= 0) {
            return "200~500万元";
        } else if (currentYearIncome.compareTo(BigDecimal.valueOf(5000000)) > 0 && currentYearIncome.compareTo(BigDecimal.valueOf(10000000)) <= 0) {
            return "500~1000万元";
        } else if (currentYearIncome.compareTo(BigDecimal.valueOf(10000000)) > 0) {
            return "1000万元以上";
        } else {
            return "";
        }
    }

    /**
     * 新增扣款记录
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:add')")
    @Log(title = "扣款记录", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping
    public AjaxResult add(@RequestBody BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        boolean status = bizDeductService.save(bizDeduct);
        bizDeduct.getCollect().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        bizDeduct.getLoopList().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        bizDeduct.getOnceList().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        status = status && (bizDeduct.getCollect().isEmpty() || statementAccountService.saveBatch(bizDeduct.getCollect()));
        status = status && (bizDeduct.getLoopList().isEmpty() || statementAccountLoopService.saveBatch(bizDeduct.getLoopList()));
        status = status && (bizDeduct.getOnceList().isEmpty() || statementAccountOnceService.saveBatch(bizDeduct.getOnceList()));
        return toAjax(status);
    }

    /**
     * 修改扣款记录
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:edit')")
    @Log(title = "扣款记录", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class)
    @PutMapping
    public AjaxResult edit(@RequestBody BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        boolean status = bizDeductService.updateById(bizDeduct);
        bizDeduct.getCollect().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        bizDeduct.getLoopList().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        bizDeduct.getOnceList().forEach(l -> {
            l.setDeductId(bizDeduct.getId());
            l.setTenantId(bizDeduct.getTenantId());
            l.setEntrustOrderId(bizDeduct.getEntrustOrderId());
        });
        BizStatementAccount delCondition = new BizStatementAccount();
        delCondition.setDeductId(bizDeduct.getId());
        statementAccountService.physicalDelete(delCondition);
        BizStatementAccountLoop delLoopCondition = new BizStatementAccountLoop();
        delLoopCondition.setDeductId(bizDeduct.getId());
        statementAccountLoopService.physicalDelete(delLoopCondition);
        BizStatementAccountOnce delOnceCondition = new BizStatementAccountOnce();
        delOnceCondition.setDeductId(bizDeduct.getId());
        statementAccountOnceService.physicalDelete(delOnceCondition);
        status = status && (bizDeduct.getCollect().isEmpty() || statementAccountService.saveBatch(bizDeduct.getCollect()));
        status = status && (bizDeduct.getLoopList().isEmpty() || statementAccountLoopService.saveBatch(bizDeduct.getLoopList()));
        status = status && (bizDeduct.getOnceList().isEmpty() || statementAccountOnceService.saveBatch(bizDeduct.getOnceList()));
        return toAjax(status);
    }

    /**
     * 删除扣款记录
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:remove')")
    @Log(title = "扣款记录", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable List<Long> ids) {
        QueryWrapper<BizStatementAccount> removeQuery = new QueryWrapper<>();
        removeQuery.in("deduct_id", ids);
        QueryWrapper<BizStatementAccountLoop> removeLoopQuery = new QueryWrapper<>();
        removeLoopQuery.in("deduct_id", ids);
        QueryWrapper<BizStatementAccountOnce> removeOnceQuery = new QueryWrapper<>();
        removeOnceQuery.in("deduct_id", ids);
        statementAccountOnceService.remove(removeOnceQuery);
        statementAccountLoopService.remove(removeLoopQuery);
        statementAccountService.remove(removeQuery);
        boolean status = bizDeductService.removeBatchByIds(ids);
        return toAjax(status);
    }


    /**
     * 获取扣款记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:query')")
    @GetMapping(value = "/checkStatementAccount/{entrustOrderId}")
    public AjaxResult checkStatementAccount(@PathVariable Long entrustOrderId) {
        // 判断最后一个对账单是哪个月的
        BizDeduct deduct = bizDeductService.query().eq("entrust_order_id", entrustOrderId).orderByDesc("year", "month").last("limit 1").one();
        DateTime prev = DateTime.now().offsetNew(DateField.MONTH, -1);
        DateTime current = DateTime.now();
        if (deduct == null) {
            // 假设没有对账单则自动返回上个月
            return success(prev.toString("yyyy-MM-01"));
        } else if (prev.toString("yyyy").equals(deduct.getYear()) && prev.toString("MM").equals(deduct.getMonth())) {
            // 假设上个月已对账返回本月
            return success(current.toString("yyyy-MM-01"));
        } else if ((current.toString("yyyy").equals(deduct.getYear()) && current.toString("MM").equals(deduct.getMonth()))) {
            // 假设本月已对账返回错误
            return error("本月已对账，无法对下月进行对账。");
        } else {
            // 其他 对最后一个对账单的下个月进行对账
            DateTime then = DateTime.of(deduct.getYear() + "-" + deduct.getMonth() + "-01", "yyyy-MM-dd").offsetNew(DateField.MONTH, 1);
            return success(then.toString("yyyy-MM-01"));
        }
    }

    /**
     * 新增扣款记录
     */
    @PreAuthorize("@ss.hasPermi('business:deduct:confirm')")
    @Log(title = "扣款记录", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/confirm")
    public AjaxResult confirmDeduct(@RequestBody BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {

        // 扣款
        List<BizDeposit> deposits = depositService.query().eq("entrust_order_id", bizDeduct.getEntrustOrderId()).ge("remain_amount", 0).eq("status", 1).orderByAsc("verify_date", "type").list();
        BigDecimal amount = bizDeduct.getAmount();
        int index = 0;
        while (amount.compareTo(BigDecimal.ZERO) > 0) {
            if(deposits.isEmpty()){
                return error("扣款失败，余额不足。");
            }
            BigDecimal money = new BigDecimal(0);

            for (BizDeposit d : deposits) {
                money = money.add(d.getRemainAmount());
            }
            if(money.compareTo(amount)<0){
                return error("扣款失败，余额不足。");
            }


            if (deposits.get(index).getRemainAmount().compareTo(amount) > 0) {
                BigDecimal remain = deposits.get(index).getRemainAmount().subtract(amount).setScale(2, RoundingMode.HALF_UP);
                amount = BigDecimal.ZERO;
                deposits.get(index).setRemainAmount(remain);
            } else {
                amount = amount.subtract(deposits.get(index).getRemainAmount()).setScale(2, RoundingMode.HALF_UP);
                deposits.get(index).setRemainAmount(BigDecimal.ZERO);
            }
            index++;
        }
        bizDeduct.setStatus(2);
        bizDeduct.setDeductDate(new Date());
        boolean status = bizDeductService.updateById(bizDeduct);
        depositService.updateBatchById(deposits);
        return toAjax(status);
    }

    @PreAuthorize("@ss.hasAnyPermi('business:deduct:reject,business:deduct:confirm')")
    @Log(title = "扣款记录", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/reject")
    public AjaxResult rejectDeduct(@RequestBody BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        bizDeduct.setStatus(4);
        boolean status = bizDeductService.updateById(bizDeduct);
        return toAjax(status);
    }

    @PreAuthorize("@ss.hasPermi('business:deduct:verify')")
    @Log(title = "扣款记录", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/verify")
    public AjaxResult verifyDeduct(@RequestBody BizDeduct bizDeduct) throws NoSuchFieldException, IllegalAccessException {
        bizDeduct.setStatus(2);
        // 到存款记录中扣款
        boolean status = bizDeductService.updateById(bizDeduct);
        return toAjax(status);
    }
}
