package com.jsh.erp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jsh.erp.datasource.dto.TaskStocktakingDTO;
import com.jsh.erp.datasource.dto.TaskStocktakingItemQueryDTO;
import com.jsh.erp.datasource.dto.TaskStocktakingQueryDTO;
import com.jsh.erp.datasource.entities.*;
import com.jsh.erp.datasource.mappers.*;
import com.jsh.erp.datasource.pda.dto.PDATaskStocktakingItemDTO;
import com.jsh.erp.datasource.pda.vo.PDATaskStocktakingItemVO;
import com.jsh.erp.datasource.pda.vo.PDATaskStocktakingVO;
import com.jsh.erp.datasource.vo.TaskStocktakingItemVO;
import com.jsh.erp.datasource.vo.TaskStocktakingVO;
import com.jsh.erp.query.LambdaQueryWrapperX;
import com.jsh.erp.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class TaskStocktakingServiceImpl extends ServiceImpl<TaskStocktakingMapper, TaskStocktaking> implements TaskStocktakingService {


    private final MaterialExtendMapper materialExtendMapper;

    private final UserMapper userMapper;

    private final DepotService depotService;

    private final TaskStocktakingItemMapper taskStocktakingItemMapper;

    private final TaskStocktakingMapper taskStocktakingMapper;

    private final MaterialMapper materialMapper;

    private final UserService userService;

    private final SequenceService sequenceService;

    private final MaterialBatchMapper materialBatchMapper;

    @Override
    public List<TaskStocktakingVO> listBy(TaskStocktakingQueryDTO taskStocktakingQueryDTO) {
        return taskStocktakingMapper.listBy(taskStocktakingQueryDTO);
    }

    /**
     * 创建盘点任务
     * @param taskStocktakingDTO
     * @return
     */
    @Override
    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
    public boolean add(TaskStocktakingDTO taskStocktakingDTO) {
        try {
            List<String> collect;
            List<MaterialBatch> materialBatchList;
            //全盘，抽盘，处理任务明细
            if (taskStocktakingDTO.getTaskType() == 1) {
                materialBatchList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().ne(MaterialBatch::getInventory, BigDecimal.ZERO).isNotNull(MaterialBatch::getInventory).eq(MaterialBatch::getDepotId,taskStocktakingDTO.getDepotId()));
                collect = materialBatchList
                        .stream()
                        .map(MaterialBatch::getPosition)
                        .collect(Collectors.toList());
                List<Long> materialIdList = materialBatchList.stream().map(MaterialBatch::getMaterialId).distinct().collect(Collectors.toList());
                List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
                List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
                taskStocktakingDTO.setCategoryCount(categoryIdList.size());
                taskStocktakingDTO.setMaterialCount(materialBatchList.size());
            } else {
                materialBatchList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().in(MaterialBatch::getBatchNumber, taskStocktakingDTO.getMaterialExtendIdList()));
                collect = materialBatchList.stream().map(MaterialBatch::getPosition).collect(Collectors.toList());
                List<Long> materialIdList = materialBatchList.stream().map(MaterialBatch::getMaterialId).collect(Collectors.toList());
                List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
                List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
                taskStocktakingDTO.setCategoryCount(categoryIdList.size());
                taskStocktakingDTO.setMaterialCount(materialBatchList.size());
            }
            //处理商品库位范围处理
            String positionRange = extractRangePair(collect);
            taskStocktakingDTO.setPositionRange(positionRange);
            User currentUser = userService.getCurrentUser();
            taskStocktakingDTO.setCreateBy(currentUser.getId());
            taskStocktakingDTO.setCreateTime(new Date());
            taskStocktakingDTO.setTaskStatus(1);
            //生成单据编号
            taskStocktakingDTO.setNumber("PDRW"+sequenceService.buildOnlyNumber());
            //生成任务
            this.save(taskStocktakingDTO);
            //生成任务明细
            List<TaskStocktakingItem> taskStocktakingItemList = new ArrayList<>();
            materialBatchList.forEach(item -> {
                TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
                taskStocktakingItem.setTaskStocktakingId(taskStocktakingDTO.getId());
                taskStocktakingItem.setMaterialItemId(item.getId());
                taskStocktakingItemList.add(taskStocktakingItem);
            });
            taskStocktakingItemMapper.insertBatch(taskStocktakingItemList);
        } catch (Exception e) {
            log.error("创建盘点任务失败", e);
            return false;
        }
        return true;
    }

    /**
     * 任务-详情
     * @param id 任务ID
     * @return
     * @throws Exception
     */
    @Override
    public TaskStocktakingVO detail(Long id) throws Exception{
        TaskStocktaking one = getOne(new LambdaQueryWrapperX<TaskStocktaking>().eq(TaskStocktaking::getId, id));
        TaskStocktakingVO taskStocktakingVO = new TaskStocktakingVO();
        BeanUtils.copyProperties(one, taskStocktakingVO);
        //获取负责人名称
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreator()));
        if (user != null) {
            taskStocktakingVO.setCreatorName(user.getUsername());
        }
        //获取创建人名称
        User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreateBy()));
        if (user1 != null) {
            taskStocktakingVO.setCreateByName(user1.getUsername());
        }
        //获取盘点人名称
        User user2 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getOperBy()));
        if (user2 != null) {
            taskStocktakingVO.setOperByName(user2.getUsername());
        }
        //获取仓库名称
        Depot depot = depotService.getDepot(one.getDepotId());
        taskStocktakingVO.setDepotName(depot.getName());
        //当任务类型是抽盘时，返回商品盘点信息
        return taskStocktakingVO;
    }

    /**
     * 任务详情-修改
     * @param taskStocktakingDTO
     * @return
     */
    @Override
    public boolean detailUpdate(TaskStocktakingDTO taskStocktakingDTO) {
        try {
            List<String> collect;
            List<MaterialBatch> materialExtendList;
            //全盘，抽盘，处理任务明细
            if (taskStocktakingDTO.getTaskType() == 1) {
                materialExtendList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().ne(MaterialBatch::getInventory, BigDecimal.ZERO).isNotNull(MaterialBatch::getInventory).eq(MaterialBatch::getDepotId,taskStocktakingDTO.getDepotId()));
                collect = materialExtendList
                        .stream()
                        .map(MaterialBatch::getPosition)
                        .collect(Collectors.toList());
                List<Long> materialIdList = materialExtendList.stream().map(MaterialBatch::getMaterialId).distinct().collect(Collectors.toList());
                List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().eq(Material::getId, materialIdList));
                List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
                taskStocktakingDTO.setCategoryCount(categoryIdList.size());
                taskStocktakingDTO.setMaterialCount(materialExtendList.size());
            } else {
                materialExtendList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().in(MaterialBatch::getBatchNumber, taskStocktakingDTO.getMaterialExtendIdList()));
                collect = materialExtendList.stream().map(MaterialBatch::getPosition).collect(Collectors.toList());
                List<Long> materialIdList = materialExtendList.stream().map(MaterialBatch::getMaterialId).collect(Collectors.toList());
                List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
                List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
                taskStocktakingDTO.setCategoryCount(categoryIdList.size());
                taskStocktakingDTO.setMaterialCount(materialExtendList.size());
            }
            //处理商品库位范围处理
            String positionRange = extractRangePair(collect);
            taskStocktakingDTO.setPositionRange(positionRange);
            User currentUser = userService.getCurrentUser();
            taskStocktakingDTO.setCreateBy(currentUser.getId());
            taskStocktakingDTO.setCreateTime(new Date());
            taskStocktakingDTO.setTaskStatus(1);
            //生成任务
            this.updateById(taskStocktakingDTO);
            List<Long> taskStocktakingItemIdList = taskStocktakingItemMapper.selectList(new LambdaQueryWrapperX<TaskStocktakingItem>().eq(TaskStocktakingItem::getTaskStocktakingId, taskStocktakingDTO.getId())).stream().map(TaskStocktakingItem::getId).collect(Collectors.toList());
            //生成任务明细
            List<TaskStocktakingItem> addTaskStocktakingItemList = new ArrayList<>();
            materialExtendList.forEach(item -> {
                if (!taskStocktakingItemIdList.contains(item.getId())) {
                    TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
                    taskStocktakingItem.setTaskStocktakingId(taskStocktakingDTO.getId());
                    taskStocktakingItem.setMaterialItemId(item.getId());
                    addTaskStocktakingItemList.add(taskStocktakingItem);
                }
            });
            List<Long> materialExtendIdList = materialExtendList.stream().map(MaterialBatch::getId).collect(Collectors.toList());
            taskStocktakingItemIdList.forEach(item -> {
                if (!materialExtendIdList.contains(item)) {
                    TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
                    taskStocktakingItem.setId(item);
                    taskStocktakingItem.setDeleteFlag(true);
                    taskStocktakingItemMapper.updateById(taskStocktakingItem);
                }
            });
            if (addTaskStocktakingItemList.size() > 0) {
                taskStocktakingItemMapper.insertBatch(addTaskStocktakingItemList);
            }
        } catch (Exception e) {
            log.error("修改盘点任务失败", e);
            return false;
        }
        return true;
    }

    /**
     * 任务详情-商品明细
     * @param taskStocktakingItemQueryDTO 筛选参数
     * @return
     */
    @Override
    public List<TaskStocktakingItemVO> listByTaskStocktakingId(TaskStocktakingItemQueryDTO taskStocktakingItemQueryDTO) {
        return taskStocktakingItemMapper.listByTaskStocktakingId(taskStocktakingItemQueryDTO);
    }

    /**
     * PDA-盘点任务列表
     * @param number 盘点单号或者任务名称
     * @param taskStatus 盘点任务状态
     * @return
     */
    @Override
    public List<PDATaskStocktakingVO> pdaList(String number , Integer taskStatus, Long depotId) {
        return taskStocktakingMapper.pdaList(number , taskStatus, depotId);
    }

    /**
     * PDA-盘点任务详情
     * @param id 盘点任务ID
     * @return
     * @throws Exception
     */
    @Override
    public TaskStocktakingVO pdaDetail(Long id) throws Exception{
        TaskStocktakingVO detail = detail(id);
        List<TaskStocktakingItem> itemList = taskStocktakingItemMapper.selectList(new LambdaQueryWrapper<TaskStocktakingItem>().eq(TaskStocktakingItem::getTaskStocktakingId, id));
        //已操作数量
        long finishCount = itemList.stream().filter(item -> item.getCreator() != null).count();
        //操作人数
        long operCount = itemList.stream().filter(item -> item.getCreator() != null).map(TaskStocktakingItem::getCreator).distinct().count();
        //商品总数量
        long itemCount = itemList.size();
        //商品差异条数
        long itemDifferenceCount = itemList.stream().filter(item -> item.getCreator() != null
                && item.getDifferenceCount() != null
                && item.getDifferenceCount() > 0).count();
        //差异率
        double differenceRate = 0;
        //准确率
        double accuracyRate = 100;
        if (itemDifferenceCount > 0) {
            //差异率 = 商品差异条数/商品总数量*100%
            differenceRate = BigDecimal.valueOf(itemDifferenceCount)
                    .divide(BigDecimal.valueOf(itemCount), 4, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(100))
                    .doubleValue();
            //准确数 = 已操作数量-商品差异条数
            BigDecimal subtract = BigDecimal.valueOf(finishCount).subtract(BigDecimal.valueOf(itemDifferenceCount));
            //准确率 = 准确数/商品总数量*100%
            if (!subtract.equals(BigDecimal.ZERO)) {
                accuracyRate = subtract.divide(BigDecimal.valueOf(itemCount), 4, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .doubleValue();
            }
        }
        detail.setItemCount(itemCount);
        detail.setDifferenceRate(differenceRate);
        detail.setAccuracyRate(accuracyRate);
        detail.setFinishCount(finishCount);
        detail.setOperCount(operCount);
        return detail;
    }

    @Override
    public List<PDATaskStocktakingItemVO> pdaItemList(PDATaskStocktakingItemDTO pdaTaskStocktakingItemDTO) {
        return taskStocktakingItemMapper.pdaList(pdaTaskStocktakingItemDTO);
    }

    /**
     * 计算库位范围
     * @param data 库位集合
     * @return
     */
    public static String extractRangePair(List<String> data) {
        // 用于存储提取的前两部分
        List<String> rangeParts = new ArrayList<>();

        for (String item : data) {
            if (item != null){
                // 提取前两部分（假设格式固定，以 "-" 分割，取前两部分）
                String[] parts = item.split("-");
                if (parts.length >= 2) {
                    String rangePart = parts[0] + "-" + parts[1];
                    rangeParts.add(rangePart); // 添加到列表
                }
            }
        }
        // 如果范围为空，直接返回空字符串
        if (rangeParts.isEmpty()) {
            return "";
        }
        // 找到最小和最大范围
        String minRange = Collections.min(rangeParts); // 字典序最小
        String maxRange = Collections.max(rangeParts); // 字典序最大
        // 返回范围对
        return minRange + "——" + maxRange;
    }
}
