package com.gree.mall.manager.logic.settle;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.settle.*;
import com.gree.mall.manager.commonmapper.CommonMapper;
import com.gree.mall.manager.enums.IsYesNoEnum;
import com.gree.mall.manager.enums.NoticeEnum;
import com.gree.mall.manager.enums.SettleWagesStatusEnum;
import com.gree.mall.manager.enums.workorder.SettleExpenseStatusEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.logic.common.WxPubNoticeLogic;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.zfire.bean.ZfireParamBean;
import com.gree.mall.manager.zfire.util.FieldUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class SettleMonthWagesLogic {
    private final CommonLogic commonLogic;
    private final CommonMapper commonMapper;
    private final SettleMonthWagesService settleMonthWagesService;
    private final SettleMonthWagesWorkerService settleMonthWagesWorkerService;
    private final SettleMonthWagesDetailService settleMonthWagesDetailService;
    private final SettleExpenseService settleExpenseService;
    private final SettleExpenseItemService settleExpenseItemService;
    private final NoticeRecordService noticeRecordService;
    private final WxPubNoticeLogic wxPubNoticeLogic;

    public IPage<SettleMonthWagesVO> gatherList(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        FieldUtils.supplyParam(zfireParamBean, SettleExpenseVO.class, adminUser);

        return commonMapper.settleMonthWagesGatherList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);
    }

    public IPage<SettleMonthWagesWorkerVO> list(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        FieldUtils.supplyParam(zfireParamBean, SettleMonthWagesWorkerVO.class, adminUser);

        return commonMapper.settleMonthWagesList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);
    }

    @Transactional
    public void batchReject(AdminUserCom adminUser, List<String> ids) {
        if (Objects.isNull(adminUser.getAdminCompanyWechat())) {
            throw new RemoteServiceException("非商户账号，驳回失败");
        }
        final List<SettleMonthWages> monthWagesList = settleMonthWagesService.lambdaQuery()
                .eq(SettleMonthWages::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .in(SettleMonthWages::getId, ids)
                .eq(SettleMonthWages::getStatus, SettleWagesStatusEnum.NOT.getKey())
                .list();
        if (CollectionUtil.isEmpty(monthWagesList)) {
            throw new RemoteServiceException("驳回单据为空");
        }
        final List<String> idList = monthWagesList.stream().map(SettleMonthWages::getId).collect(Collectors.toList());
        settleMonthWagesService.lambdaUpdate()
                .in(SettleMonthWages::getId, idList)
                .remove();
        settleMonthWagesWorkerService.lambdaUpdate()
                .in(SettleMonthWagesWorker::getSettleMonthWagesId, idList)
                .remove();
        settleExpenseService.lambdaUpdate()
                .set(SettleExpense::getRejectBy, adminUser.getNickName())
                .set(SettleExpense::getRejectTime, DateUtil.date())
                .set(SettleExpense::getGatherBy, null)
                .set(SettleExpense::getGatherTime, null)
                .set(SettleExpense::getGatherBatchNo, null)
                .set(SettleExpense::getName, null)
                .set(SettleExpense::getStatus, SettleExpenseStatusEnum.NOT.getKey())
                .eq(SettleExpense::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .in(SettleExpense::getGatherBatchNo, idList)
                .update();
        settleExpenseItemService.lambdaUpdate()
                .set(SettleExpenseItem::getSettleMonthWagesId, null)
                .in(SettleExpenseItem::getSettleMonthWagesId, idList)
                .update();
    }

    @Transactional
    public void batchSend(AdminUserCom adminUser, MonthGatherBean bean) {
        if (Objects.isNull(adminUser.getAdminCompanyWechat())) {
            throw new RemoteServiceException("非商户账号，发放失败");
        }
        final List<SettleMonthWages> monthWagesList = settleMonthWagesService.lambdaQuery()
                .eq(SettleMonthWages::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .in(SettleMonthWages::getId, bean.getIds())
                .in(SettleMonthWages::getStatus, SettleWagesStatusEnum.NOT.getKey(), SettleWagesStatusEnum.PART.getKey())
                .list();
        if (CollectionUtil.isEmpty(monthWagesList)) {
            throw new RemoteServiceException("发放单据为空");
        }
        if (Objects.isNull(bean.getSendDate())) {
            throw new RemoteServiceException("发放时间不能为空");
        }

        final List<String> monthIdList = monthWagesList.stream().map(SettleMonthWages::getId).collect(Collectors.toList());
        List<SettleMonthWagesDetail> detailList = new ArrayList<>();
        final DateTime curDate = DateUtil.date();
        for (SettleMonthWages monthWages : monthWagesList) {
            monthWages.setWaitAmount(BigDecimal.ZERO)
                    .setWaitByCount(0)
                    .setSendAmount(monthWages.getSettleAmount())
                    .setSendByCount(monthWages.getSettleByCount())
                    .setLastSendBy(adminUser.getNickName())
                    .setStatus(SettleWagesStatusEnum.END.getKey())
                    .setLastSendTime(curDate);

            SettleMonthWagesDetail detail = new SettleMonthWagesDetail();
            detail.setSettleMonthWagesId(monthWages.getId())
                    .setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId())
                    .setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName())
                    .setSendDate(bean.getSendDate())
                    .setFileUrl(bean.getFileUrl())
                    .setRemark(bean.getRemark());
            detailList.add(detail);
        }
        settleMonthWagesService.saveOrUpdateBatch(monthWagesList);
        settleMonthWagesDetailService.saveBatch(detailList);

        // 查询出未发放状态的师傅
        List<SettleMonthWagesWorker> workerList = settleMonthWagesWorkerService.lambdaQuery()
                .eq(SettleMonthWagesWorker::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .eq(SettleMonthWagesWorker::getStatus, SettleWagesStatusEnum.NOT.getKey())
                .in(SettleMonthWagesWorker::getSettleMonthWagesId, monthIdList)
                .list();
        List<NoticeRecord> records = new ArrayList<>();

        final Map<String, SettleMonthWagesDetail> detailMap = detailList.stream()
                .collect(Collectors.toMap(SettleMonthWagesDetail::getSettleMonthWagesId, Function.identity()));
        // 注入发放详情id
        for (SettleMonthWagesWorker wagesWorker : workerList) {
            if (detailMap.containsKey(wagesWorker.getSettleMonthWagesId())) {
                final SettleMonthWagesDetail wagesDetail = detailMap.get(wagesWorker.getSettleMonthWagesId());
                wagesWorker.setSettleMonthWagesDetailId(wagesDetail.getId());
            }
            wagesWorker.setStatus(SettleWagesStatusEnum.END.getKey());

            // 发系统公告
            String content =  wagesWorker.getName() + "安维费用发放";
            NoticeRecord noticeRecord = new NoticeRecord();
            noticeRecord.setNoticeId(wagesWorker.getSettleMonthWagesId());
            noticeRecord.setTitle("安维费用发放");
            noticeRecord.setContent("您于" + DateUtil.formatDateTime(curDate) + "收到 " + content);
            noticeRecord.setType(NoticeEnum.B.getKey());
            noticeRecord.setIsNotice(IsYesNoEnum.YES.getKey());
            noticeRecord.setReadFlag(IsYesNoEnum.NO.getKey());
            noticeRecord.setAdminUserId(adminUser.getAdminUserId());
            noticeRecord.setAdminNickName(adminUser.getNickName());
            noticeRecord.setIsWorker(IsYesNoEnum.YES.getKey());
            noticeRecord.setIssueTime(curDate);
            noticeRecord.setAdminCompanyId(wagesWorker.getWorkerId());
            noticeRecord.setAdminCompanyName(adminUser.getAdminCompanyWechat().getCompanyName());
            noticeRecord.setNoticeType("NOTICE");
            noticeRecord.setOrderId(wagesWorker.getSettleMonthWagesId());
            records.add(noticeRecord);

            try {
                wxPubNoticeLogic.addSettleNotice(wagesWorker.getWorkerMobile(), wagesWorker.getCompanyWechatId(),
                        content, wagesWorker.getWorkerName(), wagesWorker.getSettleAmount(),
                        bean.getSendDate(), adminUser.getAdminCompanyWechat().getCompanyName());
            } catch (Exception e) {
                log.error("发送消息模板出错>>>" + e.getMessage());
            }
        }
        settleMonthWagesWorkerService.saveOrUpdateBatch(workerList);
        noticeRecordService.saveBatch(records);
    }

    public void workerBatchSend(AdminUserCom adminUser, MonthGatherBean bean) {
        if (Objects.isNull(adminUser.getAdminCompanyWechat())) {
            throw new RemoteServiceException("非商户账号，发放失败");
        }
        if (StringUtils.isBlank(bean.getSettleMonthWagesId())) {
            throw new RemoteServiceException("月度工资汇总id不能为空");
        }
        final SettleMonthWages settleMonthWages = settleMonthWagesService.lambdaQuery()
                .eq(SettleMonthWages::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .eq(SettleMonthWages::getId, bean.getSettleMonthWagesId())
                .in(SettleMonthWages::getStatus, SettleWagesStatusEnum.NOT.getKey(), SettleWagesStatusEnum.PART.getKey())
                .one();
        if (Objects.isNull(settleMonthWages)) {
            throw new RemoteServiceException("月度工资汇总单据不存在");
        }

        // 查询未发放师傅
        List<SettleMonthWagesWorker> workerList = settleMonthWagesWorkerService.lambdaQuery()
                .eq(SettleMonthWagesWorker::getSettleMonthWagesId, bean.getSettleMonthWagesId())
                .eq(SettleMonthWagesWorker::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .eq(SettleMonthWagesWorker::getStatus, SettleWagesStatusEnum.NOT.getKey())
                .in(SettleMonthWagesWorker::getId, bean.getIds())
                .list();

        if (CollectionUtil.isEmpty(workerList)) {
            throw new RemoteServiceException("月度工资未发放师傅不存在");
        }
        final DateTime curDate = DateUtil.date();

        // 插入月度汇总详情
        SettleMonthWagesDetail detail = new SettleMonthWagesDetail();
        detail.setSettleMonthWagesId(bean.getSettleMonthWagesId())
                .setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName())
                .setSendDate(bean.getSendDate())
                .setFileUrl(bean.getFileUrl())
                .setRemark(bean.getRemark())
                .insert();

        List<NoticeRecord> records = new ArrayList<>();

        for (SettleMonthWagesWorker wagesWorker : workerList) {
            wagesWorker.setStatus(SettleWagesStatusEnum.END.getKey())
                    .setSettleMonthWagesDetailId(detail.getId());

            // 发系统公告
            String content = wagesWorker.getName() + "安维费用发放";
            NoticeRecord noticeRecord = new NoticeRecord();
            noticeRecord.setNoticeId(wagesWorker.getSettleMonthWagesId());
            noticeRecord.setTitle("安维费用发放");
            noticeRecord.setContent("您于" + DateUtil.formatDateTime(curDate) + "收到 " + content);
            noticeRecord.setType(NoticeEnum.B.getKey());
            noticeRecord.setIsNotice(IsYesNoEnum.YES.getKey());
            noticeRecord.setReadFlag(IsYesNoEnum.NO.getKey());
            noticeRecord.setAdminUserId(adminUser.getAdminUserId());
            noticeRecord.setAdminNickName(adminUser.getNickName());
            noticeRecord.setIsWorker(IsYesNoEnum.YES.getKey());
            noticeRecord.setIssueTime(curDate);
            noticeRecord.setAdminCompanyId(wagesWorker.getWorkerId());
            noticeRecord.setAdminCompanyName(adminUser.getAdminCompanyWechat().getCompanyName());
            noticeRecord.setNoticeType("NOTICE");
            noticeRecord.setOrderId(wagesWorker.getSettleMonthWagesId());
            records.add(noticeRecord);

            try {
                wxPubNoticeLogic.addSettleNotice(wagesWorker.getWorkerMobile(), wagesWorker.getCompanyWechatId(),
                        content, wagesWorker.getWorkerName(), wagesWorker.getSettleAmount(),
                        bean.getSendDate(), adminUser.getAdminCompanyWechat().getCompanyName());
            } catch (Exception e) {
                log.error("发送消息模板出错>>>" + e.getMessage());
            }
        }
        // 更新为已发放师傅
        settleMonthWagesWorkerService.saveOrUpdateBatch(workerList);
        noticeRecordService.saveBatch(records);

        // 统计月度汇总已发人数、已发金额、未发人数、未发金额
        final List<SettleMonthWagesWorker> computeWorkerList = settleMonthWagesWorkerService.lambdaQuery()
                .eq(SettleMonthWagesWorker::getSettleMonthWagesId, bean.getSettleMonthWagesId())
                .eq(SettleMonthWagesWorker::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .list();

        final List<SettleMonthWagesWorker> endList = computeWorkerList.stream()
                .filter(v -> v.getStatus().equals(SettleWagesStatusEnum.END.getKey()))
                .collect(Collectors.toList());

        final List<SettleMonthWagesWorker> notList = computeWorkerList.stream()
                .filter(v -> v.getStatus().equals(SettleWagesStatusEnum.NOT.getKey()))
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(notList)) {
            // 未发现剩余发放师傅
            settleMonthWages.setStatus(SettleWagesStatusEnum.END.getKey())
                    .setSendByCount(settleMonthWages.getSettleByCount())
                    .setSendAmount(settleMonthWages.getSettleAmount())
                    .setWaitByCount(0)
                    .setWaitAmount(BigDecimal.ZERO)
                    .setLastSendTime(curDate)
                    .setLastSendBy(adminUser.getNickName())
                    .updateById();
            return;
        }

        BigDecimal sendAmount = BigDecimal.ZERO;
        int sendByCount = endList.size();
        for (SettleMonthWagesWorker worker : endList) {
            sendAmount = sendAmount.add(worker.getSettleAmount());
        }

        BigDecimal waitAmount = BigDecimal.ZERO;
        int waitByCount = notList.size();
        for (SettleMonthWagesWorker worker : notList) {
            waitAmount = waitAmount.add(worker.getSettleAmount());
        }
        settleMonthWages.setStatus(SettleWagesStatusEnum.PART.getKey())
                .setSendByCount(sendByCount)
                .setSendAmount(sendAmount)
                .setWaitByCount(waitByCount)
                .setWaitAmount(waitAmount)
                .setLastSendTime(curDate)
                .setLastSendBy(adminUser.getNickName())
                .updateById();
    }

}
