package com.bonus.material.purchase.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import com.bonus.common.biz.constant.BmConfigItems;
import com.bonus.common.biz.enums.MaTypeManageTypeEnum;
import com.bonus.common.biz.enums.PurchaseTaskStatusEnum;
import com.bonus.common.biz.enums.TmTaskTypeEnum;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.basic.domain.BmFileInfo;
import com.bonus.material.basic.mapper.BmFileInfoMapper;
import com.bonus.material.basic.service.IBmConfigService;
import com.bonus.material.purchase.domain.PurchaseCheckDetails;
import com.bonus.material.purchase.domain.dto.PurchaseCheckDto;
import com.bonus.material.purchase.domain.dto.PurchaseQueryDto;
import com.bonus.material.purchase.domain.vo.PurchaseVerifyVo;
import com.bonus.material.purchase.mapper.PurchaseCheckDetailsMapper;
import com.bonus.material.purchase.domain.vo.PurchaseCheckFormVo;
import com.bonus.material.purchase.mapper.PurchaseMacodeInfoMapper;
import com.bonus.material.task.domain.TmTask;
import com.bonus.material.task.mapper.TmTaskMapper;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import com.bonus.material.purchase.mapper.PurchaseCheckInfoMapper;
import com.bonus.material.purchase.domain.PurchaseCheckInfo;
import com.bonus.material.purchase.service.IPurchaseCheckInfoService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;

/**
 * 新购验收任务Service业务层处理
 * 
 * @author syruan
 */
@Service
public class PurchaseCheckInfoServiceImpl implements IPurchaseCheckInfoService {

    public static final String PURCHASE_TASK_TYPE_LABEL = "XG";

    @Autowired
    private IBmConfigService bmConfigService;

    @Resource
    private PurchaseCheckInfoMapper purchaseCheckInfoMapper;

    @Resource
    private PurchaseCheckDetailsMapper purchaseCheckDetailsMapper;

    @Autowired
    private PurchaseMacodeInfoMapper purchaseMacodeInfoMapper;

    @Resource
    private TmTaskMapper tmTaskMapper;

    @Resource
    BmFileInfoMapper bmFileInfoMapper;

    /**
     * 查询新购验收任务
     * 
     * @param purchaseQueryDto 新购验收任务请求参数封装dto
     * @return 新购验收任务
     */
    @Override
    public PurchaseCheckDto selectPurchaseCheckInfoById(PurchaseQueryDto purchaseQueryDto) {
        PurchaseCheckDto purchaseCheckDtoResult = new PurchaseCheckDto();
        PurchaseCheckInfo purchaseCheckInfo = purchaseCheckInfoMapper.selectPurchaseCheckInfoById(purchaseQueryDto.getId());
        if (purchaseCheckInfo != null) {
            purchaseCheckDtoResult.setPurchaseCheckInfo(purchaseCheckInfo);
            boolean isAllowPartTransfer = bmConfigService.isBmConfigEnabledWithDefaultFalse(BmConfigItems.BOOLEAN_ALLOW_PURCHASE_PART_TRANSFER);
            List<PurchaseCheckDetails> purchaseCheckDetailsList;
            if (isAllowPartTransfer) {
                purchaseCheckDetailsList = purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListByQueryDto(purchaseQueryDto);
                if (purchaseQueryDto.getStatusList().contains(PurchaseTaskStatusEnum.TO_STORE.getStatus())) {
                    purchaseCheckDetailsList = purchaseCheckDetailsList.stream()
                            .filter(o -> MaTypeManageTypeEnum.NUMBER_DEVICE.getTypeId().equals(o.getManageType()) ||
                                    MaTypeManageTypeEnum.CODE_DEVICE.getTypeId().equals(o.getManageType()) && getPurchaseMaCodeCount(o.getTaskId(), o.getTypeId()) > 0)
                            .collect(Collectors.toList());
                }
                //针对于app查询可能存在的验收图片
                extractedFile(purchaseCheckDetailsList);
            } else {
                purchaseQueryDto.setStatusList(null);
                purchaseCheckDetailsList = purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListByQueryDto(purchaseQueryDto);
                //针对于app查询可能存在的验收图片
                extractedFile(purchaseCheckDetailsList);
            }
            purchaseCheckDtoResult.setPurchaseCheckDetailsList(purchaseCheckDetailsList);
        }
        return purchaseCheckDtoResult;
    }

    /**
     * 提取app新购验收文件信息
     * @param purchaseCheckDetailsList
     */
    private void extractedFile(List<PurchaseCheckDetails> purchaseCheckDetailsList) {
        if (!CollectionUtils.isEmpty(purchaseCheckDetailsList)) {
            for (PurchaseCheckDetails purchaseCheckDetails : purchaseCheckDetailsList) {
                BmFileInfo fileInfo = new BmFileInfo();
                fileInfo.setTaskType(10);
                fileInfo.setModelId(purchaseCheckDetails.getId());
                fileInfo.setTaskId(purchaseCheckDetails.getTaskId());
                List<BmFileInfo> bmFileInfoList = bmFileInfoMapper.selectBmFileInfoList(fileInfo);
                if (!CollectionUtils.isEmpty(bmFileInfoList)) {
                    purchaseCheckDetails.setBmFileInfos(bmFileInfoList);
                }
            }
        }
    }

    private int getPurchaseMaCodeCount(Long taskId, Long typeId) {
        return purchaseMacodeInfoMapper.getPurchaseMaCodeCount(taskId, typeId);
    }

    /**
     * 查询新购验收任务列表
     *
     * @param purchaseQueryDto 新购验收任务请求参数
     * @return 新购验收任务
     */
    @Override
    public List<PurchaseCheckInfo> selectPurchaseCheckInfoList(PurchaseQueryDto purchaseQueryDto) {
        List<PurchaseCheckInfo> purchaseCheckInfos = purchaseCheckInfoMapper.selectPurchaseCheckInfoJoinList(purchaseQueryDto);
        List<PurchaseCheckInfo> purchaseCheckInfoResult = new ArrayList<>();
        if (CollectionUtils.isEmpty(purchaseCheckInfos)) {
            return purchaseCheckInfoResult;
        }
        boolean isAllowPartTransfer = bmConfigService.isBmConfigEnabledWithDefaultFalse(BmConfigItems.BOOLEAN_ALLOW_PURCHASE_PART_TRANSFER);
        for (PurchaseCheckInfo purchaseInfo : purchaseCheckInfos) {
            List<PurchaseCheckDetails> purchaseCheckDetails = purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListByTaskId(purchaseInfo.getTaskId(), null);
            // 筛除：绑定状态 + 数量设备
            purchaseCheckDetails = purchaseCheckDetails.stream().filter(o -> !(MaTypeManageTypeEnum.NUMBER_DEVICE.getTypeId().equals(o.getManageType()) &&
                    (o.getStatus().equals(PurchaseTaskStatusEnum.TO_BIND.getStatus()) || o.getStatus().equals(PurchaseTaskStatusEnum.TO_BIND_AFTER_REJECT.getStatus())))).collect(Collectors.toList());
            OptionalInt minStatus = purchaseCheckDetails.stream().mapToInt(PurchaseCheckDetails::getStatus).min();
            if (isAllowPartTransfer) {
                if (!CollectionUtils.isEmpty(purchaseQueryDto.getStatusList())) {
                    purchaseCheckDetails = purchaseCheckDetails.stream().filter(o -> purchaseQueryDto.getStatusList().contains(o.getStatus())).collect(Collectors.toList());
                }
                purchaseInfo.setPurchaseMaTypeName(purchaseCheckDetailsMapper.selectMaTypeNameByTaskAndStatusList(purchaseInfo.getTaskId(), purchaseQueryDto.getStatusList()));
            } else {
                purchaseInfo.setPurchaseMaTypeName(purchaseCheckDetailsMapper.selectMaTypeNameByTaskAndStatusList(purchaseInfo.getTaskId(), new ArrayList<>()));
            }
            if (!CollectionUtils.isEmpty(purchaseCheckDetails)) {
                AtomicLong purchaseMaTotalNumber = new AtomicLong(0L);
                AtomicReference<BigDecimal> purchaseMaTotalPrice = new AtomicReference<>(BigDecimal.ZERO);
                for (PurchaseCheckDetails detail : purchaseCheckDetails) {
                    if (detail.getPurchaseNum() == null || detail.getPurchasePrice() == null) {
                        continue;
                    }
                    if (detail.getPurchaseNum() < 0 || detail.getPurchasePrice().compareTo(BigDecimal.ZERO) < 0) {
                        throw new IllegalArgumentException("采购数量和价格必须为非负数");
                    }
                    purchaseMaTotalNumber.addAndGet(detail.getPurchaseNum());
                    purchaseMaTotalPrice.updateAndGet(v -> v.add(new BigDecimal(detail.getPurchaseNum()).multiply(detail.getPurchasePrice())));
                }
                purchaseInfo.setPurchaseMaNumber(purchaseMaTotalNumber.get());
                purchaseInfo.setPurchasePrice(purchaseMaTotalPrice.get());
                if (purchaseInfo.getTaxRate() != null && purchaseInfo.getPurchasePrice() != null) {
                    purchaseInfo.setPurchaseTaxPrice(calculateTaxPrice(purchaseMaTotalPrice.get(), purchaseInfo.getTaxRate()));
                }
                // 设置外层任务状态：入库待开始、入库进行中、入库已完成
                TmTask tmTask = tmTaskMapper.selectTmTaskByTaskId(purchaseInfo.getTaskId());
                purchaseInfo.setTaskStatus(tmTask.getTaskStatus());
                // 设置外层任务列表
                if (isAllowPartTransfer) {
                    purchaseCheckInfoResult.add(purchaseInfo);
                } else if (minStatus.isPresent() && purchaseQueryDto.getStatusList().contains(Integer.valueOf(minStatus.getAsInt()))) {
                    // 当不允许部分物资状态流转时，例如内部状态含(2,12,3,13)，其中最小的状态值(2),当等于传入的状态值(2,12)时，才显示外面的列表
                    purchaseCheckInfoResult.add(purchaseInfo);
                }
            }
        }
        return purchaseCheckInfoResult;
    }

    /**
     * 查询新购验收任务详细列表
     *
     * @param purchaseCheckInfo 新购验收任务详细
     * @return 新购验收任务详细
     */
    @Override
    public List<PurchaseCheckDetails> selectPurchaseCheckDetailsList(PurchaseCheckInfo purchaseCheckInfo) {
        return purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListFromInfo(purchaseCheckInfo);
    }

    /**
     * 含税价格计算
     * @param purchaseNoTaxPrice 不含税价格
     * @param taxRate 税率：0~100  例如13%税率 值应该是整形:13
     * @return 不含税价格100 税率为13%，结果为 113.00
     */
    public static BigDecimal calculateTaxPrice(BigDecimal purchaseNoTaxPrice, BigDecimal taxRate) {
        BigDecimal one = BigDecimal.ONE;
        BigDecimal divisor = BigDecimal.valueOf(100);
        return purchaseNoTaxPrice.multiply(one.add(taxRate.divide(divisor))).setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 新增新购验收任务
     * 
     * @param purchaseCheckInfo 新购验收任务
     * @return 结果
     */
    @Override
    @Transactional
    public AjaxResult insertPurchaseCheckInfo(PurchaseCheckDto purchaseCheckInfo) {
        purchaseCheckInfo.getPurchaseCheckInfo().setCreateTime(DateUtils.getNowDate());
        purchaseCheckInfo.getPurchaseCheckInfo().setCreateBy(SecurityUtils.getUsername());
        try {
            int thisMonthMaxOrder = tmTaskMapper.getMonthMaxOrderByDate(DateUtils.getCurrentYear(), DateUtils.getCurrentMonth(), TmTaskTypeEnum.TM_TASK_PURCHASE.getTaskTypeId());
            String taskCode = genderTaskCode(thisMonthMaxOrder);
            TmTask tmTask = new TmTask(null, TmTaskTypeEnum.TM_TASK_PURCHASE.getTaskTypeId(),
                    PurchaseTaskStatusEnum.TASK_IN_PROGRESS.getStatus(),
                    purchaseCheckInfo.getPurchaseCheckInfo().getCompanyId(), thisMonthMaxOrder + 1, taskCode);
            tmTask.setCreateTime(DateUtils.getNowDate());
            tmTaskMapper.insertTmTask(tmTask);
            Long taskId = tmTask.getTaskId();
            purchaseCheckInfo.getPurchaseCheckInfo().setTaskId(taskId);
            int count = purchaseCheckInfoMapper.insertPurchaseCheckInfo(purchaseCheckInfo.getPurchaseCheckInfo());
            if (count > 0) {
                return insertPurchaseCheckDetails(purchaseCheckInfo.getPurchaseCheckDetailsList(), taskId);
            } else {
                return AjaxResult.error("新增任务失败,purchase_check_info表插入0条");
            }
        } catch (DataAccessException e) {
            return AjaxResult.error("数据库操作失败:" + e.getMessage());
        } catch (Exception e) {
            return AjaxResult.error("新增任务失败:" + e.getMessage());
        }
    }

    private AjaxResult insertPurchaseCheckDetails(List<PurchaseCheckDetails> purchaseCheckDetailsList, Long taskId) {
        if (!CollectionUtils.isEmpty(purchaseCheckDetailsList)) {
            for (PurchaseCheckDetails details : purchaseCheckDetailsList) {
                details.setTaskId(taskId);
                details.setStatus(PurchaseTaskStatusEnum.TO_NOTICE.getStatus());
                details.setInputStatus("0");
                List<BmFileInfo> bmFileInfos = details.getBmFileInfos();
                if (!CollectionUtils.isEmpty(bmFileInfos)) {
                    bmFileInfos.stream().forEach(o -> o.setTaskId(taskId));
                    bmFileInfoMapper.insertBmFileInfos(bmFileInfos);
                }
            }
            // 批量插入详情数据
            int count = purchaseCheckDetailsMapper.insertPurchaseCheckDetailsList(purchaseCheckDetailsList);
            if (count > 0) {
                return AjaxResult.success("新增任务成功");
            } else {
                return AjaxResult.error("新增任务失败,purchase_check_detail详情表插入0条");
            }
        } else {
            return AjaxResult.success("新增任务成功");
        }
    }

    @Override
    @Transactional
    public AjaxResult outVerify(PurchaseVerifyVo purchaseVerifyVo) {
        try {
            purchaseVerifyVo.getTaskIds().removeIf(Objects::isNull);
            int updateCount = 0;
            for (Long taskId : purchaseVerifyVo.getTaskIds()) {
                PurchaseQueryDto purchaseQueryDto = new PurchaseQueryDto();
                purchaseQueryDto.setTaskId(taskId);
                List<PurchaseCheckDetails> purchaseCheckDetails = purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListByQueryDto(purchaseQueryDto);
                List<PurchaseCheckDetails> codeList = purchaseCheckDetails.stream().filter(o -> MaTypeManageTypeEnum.CODE_DEVICE.getTypeId().equals(o.getManageType())).collect(Collectors.toList());
                List<PurchaseCheckDetails> numList = purchaseCheckDetails.stream().filter(o -> MaTypeManageTypeEnum.NUMBER_DEVICE.getTypeId().equals(o.getManageType())).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(codeList) && codeList.size() > 0) {
                    for (PurchaseCheckDetails details : codeList) {
                        details.setStatus(PurchaseTaskStatusEnum.TO_BIND.getStatus());
                        updateCount += purchaseCheckDetailsMapper.updatePurchaseDetails4Check(details);
                    }
                }
                if (!CollectionUtils.isEmpty(numList) && numList.size() > 0) {
                    for (PurchaseCheckDetails details : numList) {
                        details.setStatus(PurchaseTaskStatusEnum.TO_STORE.getStatus());
                        updateCount += purchaseCheckDetailsMapper.updatePurchaseDetails4Check(details);
                    }
                }
            }
            return updateCount > 0 ? AjaxResult.success("验证成功") : AjaxResult.error("无验证信息");
        } catch (Exception e) {
            return AjaxResult.error("验收状态更改失败,异常报错:" + e.getMessage());
        }
    }

    @Override
    @Transactional
    public AjaxResult innerVerify(PurchaseVerifyVo purchaseVerifyVo) {
        try {
            AjaxResult result = new AjaxResult();
            if (!CollectionUtils.isEmpty(purchaseVerifyVo.getPurchaseCheckDetailsList())) {
                if (BooleanUtils.isTrue(purchaseVerifyVo.getVerifyPass())) {
                    for (PurchaseCheckDetails details : purchaseVerifyVo.getPurchaseCheckDetailsList()) {
                        if (MaTypeManageTypeEnum.CODE_DEVICE.getTypeId().equals(details.getManageType())) {
                            details.setStatus(PurchaseTaskStatusEnum.TO_BIND.getStatus());
                        } else if (MaTypeManageTypeEnum.NUMBER_DEVICE.getTypeId().equals(details.getManageType())) {
                            details.setStatus(PurchaseTaskStatusEnum.TO_STORE.getStatus());
                        }
                        result = purchaseCheckDetailsMapper.updatePurchaseDetails4Check(details) > 0 ? AjaxResult.success("detail验证成功") : AjaxResult.error("details无验证信息");
                        extractedFile(details);
                    }
                } else {
                    for (PurchaseCheckDetails details : purchaseVerifyVo.getPurchaseCheckDetailsList()) {
                        details.setStatus(PurchaseTaskStatusEnum.TO_NOTICE.getStatus());
                        result = purchaseCheckDetailsMapper.updatePurchaseDetails4Check(details) > 0 ? AjaxResult.success("detail验证驳回成功") : AjaxResult.error("details无验证信息");
                        tmTaskMapper.updateTmTask(new TmTask()
                                .setTaskId(details.getTaskId())
                                .setTaskType(TmTaskTypeEnum.TM_TASK_PURCHASE.getTaskTypeId())
                                .setTaskStatus(PurchaseTaskStatusEnum.TASK_IN_PROGRESS.getStatus()));
                        extractedFile(details);
                    }
                }
            }
            return result;
        } catch (Exception e) {
            return AjaxResult.error("验收状态更改失败,异常报错:" + e.getMessage());
        }
    }

    /**
     * app新购验收图片上传方法抽取
     * @param details
     */
    private void extractedFile(PurchaseCheckDetails details) {
        if (!CollectionUtils.isEmpty(details.getBmFileInfos())) {
            for (BmFileInfo bmFileInfo : details.getBmFileInfos()) {
                if (bmFileInfo.getTaskType() != null && bmFileInfo.getTaskType() == 10) {
                    bmFileInfo.setTaskId(details.getTaskId());
                    bmFileInfo.setModelId(details.getId());
                    bmFileInfo.setCreateBy(SecurityUtils.getUsername());
                    bmFileInfo.setCreateTime(DateUtils.getNowDate());
                    bmFileInfoMapper.insertBmFileInfo(bmFileInfo);
                }
            }
        }
    }

    /**
     * 根据任务id查询验收单
     *
     * @param taskId 任务id
     */
    @Override
    public PurchaseCheckFormVo selectPurchaseCheckFormVoByTaskId(Long taskId) {
        // 执行SQL查询外层信息
        PurchaseCheckFormVo result = purchaseCheckInfoMapper.selectPurchaseCheckFormVoByTaskId(taskId);

        if (result != null) {
            // 执行SQL查询内层信息
            List<PurchaseCheckDetails> purchaseCheckDetails = purchaseCheckDetailsMapper.selectPurchaseCheckDetailsListByTaskId(taskId, null);
            // 过滤掉空数据
            purchaseCheckDetails.removeIf(Objects::isNull);
            result.setMaterialList(purchaseCheckDetails);
            return result;
        } else {
            return new PurchaseCheckFormVo();
        }
    }

    /**
     * 生成任务编号并构造Tm_Task任务对象
     * @param thisMonthMaxOrder 当月最大单号
     * @return 任务对象
     */
    private static String genderTaskCode(Integer thisMonthMaxOrder) {
        return PURCHASE_TASK_TYPE_LABEL + DateUtils.getCurrentYear() + DateUtils.getCurrentMonth() + String.format("%06d", thisMonthMaxOrder + 1);
    }

    /**
     * 修改新购验收任务
     * 
     * @param purchaseCheckDto 新购验收任务
     * @return 结果
     */
    @Override
    @Transactional
    public boolean updatePurchaseCheckInfo(PurchaseCheckDto purchaseCheckDto) {
        purchaseCheckDto.getPurchaseCheckInfo().setUpdateTime(DateUtils.getNowDate());
        purchaseCheckDto.getPurchaseCheckInfo().setUpdateBy(SecurityUtils.getUsername());
        try {
            Long[] ids = new Long[]{purchaseCheckDto.getPurchaseCheckInfo().getId()};
            purchaseCheckDetailsMapper.deletePurchaseCheckDetailsByParentIds(ids);
            insertPurchaseCheckDetails(purchaseCheckDto.getPurchaseCheckDetailsList(), purchaseCheckDto.getPurchaseCheckInfo().getTaskId());
            purchaseCheckInfoMapper.updatePurchaseCheckInfo(purchaseCheckDto.getPurchaseCheckInfo());
            return true;
        } catch (Exception e) {
            throw new ServiceException("错误信息描述");
        }
    }

    /**
     * 批量删除新购验收任务
     * 
     * @param ids 需要删除的新购验收任务主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deletePurchaseCheckInfoByIds(Long[] ids) {
        tmTaskMapper.deleteTmTaskByPurchaseIds(ids);
        purchaseCheckDetailsMapper.deletePurchaseCheckDetailsByParentIds(ids);
        return purchaseCheckInfoMapper.deletePurchaseCheckInfoByIds(ids);
    }

    /**
     * 删除新购验收任务信息
     * 
     * @param id 新购验收任务主键
     * @return 结果
     */
    @Override
    public int deletePurchaseCheckInfoById(Long id) {
        return purchaseCheckInfoMapper.deletePurchaseCheckInfoById(id);
    }
}
