package com.zt.plat.module.base.service.processinginfomationoperation;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.zt.plat.module.base.controller.admin.processinginfomationoperation.vo.*;
import com.zt.plat.module.base.dal.dataobject.processinginfomationoperation.ProcessingInfomationOperationDO;
import com.zt.plat.module.base.dal.dao.processingoperation.ProcessingOperationMapper;
import com.zt.plat.module.base.dal.dataobject.processingoperation.ProcessingOperationDO;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.pojo.PageParam;
import com.zt.plat.framework.common.util.object.BeanUtils;

import com.zt.plat.module.base.dal.dao.processinginfomationoperation.ProcessingInfomationOperationMapper;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
import static com.zt.plat.framework.common.util.collection.CollectionUtils.diffList;
import static com.zt.plat.module.base.enums.ErrorCodeConstants.*;

/**
 * 工艺工序 Service 实现类
 *
 * @author 后台管理-1
 */
@Service
@Validated
public class ProcessingInfomationOperationServiceImpl implements ProcessingInfomationOperationService {

    @Resource
    private ProcessingInfomationOperationMapper processingInfomationOperationMapper;
    @Resource
    private ProcessingOperationMapper processingOperationMapper;

    @Override
    public ProcessingInfomationOperationRespVO createProcessingInfomationOperation(ProcessingInfomationOperationSaveReqVO createReqVO) {
        // 插入
        ProcessingInfomationOperationDO processingInfomationOperation = BeanUtils.toBean(createReqVO, ProcessingInfomationOperationDO.class);
        processingInfomationOperationMapper.insert(processingInfomationOperation);
        // 返回
        return BeanUtils.toBean(processingInfomationOperation, ProcessingInfomationOperationRespVO.class);
    }

    @Override
    public void updateProcessingInfomationOperation(ProcessingInfomationOperationSaveReqVO updateReqVO) {
        // 校验存在
        validateProcessingInfomationOperationExists(updateReqVO.getId());
        // 更新
        ProcessingInfomationOperationDO updateObj = BeanUtils.toBean(updateReqVO, ProcessingInfomationOperationDO.class);
        processingInfomationOperationMapper.updateById(updateObj);
    }

    @Override
    public void deleteProcessingInfomationOperation(Long id) {
        // 校验存在
        validateProcessingInfomationOperationExists(id);
        // 删除
        processingInfomationOperationMapper.deleteById(id);
    }

    @Override
        public void deleteProcessingInfomationOperationListByIds(List<Long> ids) {
        // 校验存在
        validateProcessingInfomationOperationExists(ids);
        // 删除
        processingInfomationOperationMapper.deleteByIds(ids);
        }

    private void validateProcessingInfomationOperationExists(List<Long> ids) {
        List<ProcessingInfomationOperationDO> list = processingInfomationOperationMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(PROCESSING_INFOMATION_OPERATION_NOT_EXISTS);
        }
    }

    private void validateProcessingInfomationOperationExists(Long id) {
        if (processingInfomationOperationMapper.selectById(id) == null) {
            throw exception(PROCESSING_INFOMATION_OPERATION_NOT_EXISTS);
        }
    }

    @Override
    public ProcessingInfomationOperationDO getProcessingInfomationOperation(Long id) {
        return processingInfomationOperationMapper.selectById(id);
    }

    @Override
    public PageResult<ProcessingInfomationOperationDO> getProcessingInfomationOperationPage(ProcessingInfomationOperationPageReqVO pageReqVO) {
        return processingInfomationOperationMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ProcessingInfomationOperationRespVO> getProcessingInfomationOperationDetailPage(ProcessingInfomationOperationPageReqVO pageReqVO) {
        List<ProcessingInfomationOperationRespVO> detailList = buildDetailList(pageReqVO);
        int total = detailList.size();
        if (total == 0) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        Integer pageSize = pageReqVO.getPageSize();
        if (pageSize != null && pageSize <= 0) {
            return new PageResult<>(detailList, (long) total);
        }
        int pageNo = pageReqVO.getPageNo() == null ? 1 : pageReqVO.getPageNo();
        int size = (pageSize == null || pageSize <= 0) ? total : pageSize;
        int fromIndex = Math.max((pageNo - 1) * size, 0);
        if (fromIndex >= total) {
            return new PageResult<>(Collections.emptyList(), (long) total);
        }
        int toIndex = Math.min(fromIndex + size, total);
        return new PageResult<>(detailList.subList(fromIndex, toIndex), (long) total);
    }

    @Override
    public List<ProcessingInfomationOperationRespVO> getProcessingInfomationOperationDetailList(ProcessingInfomationOperationPageReqVO pageReqVO) {
        return buildDetailList(pageReqVO);
    }

    private List<ProcessingInfomationOperationRespVO> buildDetailList(ProcessingInfomationOperationPageReqVO pageReqVO) {
        List<ProcessingInfomationOperationDO> relations = processingInfomationOperationMapper.selectList(pageReqVO);
        if (CollUtil.isEmpty(relations)) {
            return Collections.emptyList();
        }
        Set<Long> operationIds = relations.stream()
                .flatMap(item -> Stream.of(item.getPreviousOperationId(), item.getNextOperationId()))
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Long, ProcessingOperationDO> operationMap;
        if (operationIds.isEmpty()) {
            operationMap = Collections.emptyMap();
        } else {
            List<ProcessingOperationDO> operations = processingOperationMapper.selectBatchIds(operationIds);
            if (CollUtil.isEmpty(operations)) {
                operationMap = Collections.emptyMap();
            } else {
                operationMap = operations.stream()
                        .filter(Objects::nonNull)
                        .collect(Collectors.toMap(ProcessingOperationDO::getId, Function.identity(), (v1, v2) -> v1));
            }
        }
        List<ProcessingInfomationOperationRespVO> detailList = relations.stream()
                .map(item -> convertToResp(item, operationMap))
                .collect(Collectors.toList());
        String nextCode = pageReqVO.getNextOperationCode();
        if (StrUtil.isNotBlank(nextCode)) {
            detailList = detailList.stream()
                    .filter(item -> StrUtil.containsIgnoreCase(item.getNextOperationCode(), nextCode))
                    .collect(Collectors.toList());
        }
        String nextName = pageReqVO.getNextOperationName();
        if (StrUtil.isNotBlank(nextName)) {
            detailList = detailList.stream()
                    .filter(item -> StrUtil.containsIgnoreCase(item.getNextOperationName(), nextName))
                    .collect(Collectors.toList());
        }
        return detailList;
    }

    private ProcessingInfomationOperationRespVO convertToResp(ProcessingInfomationOperationDO relation,
                                                               Map<Long, ProcessingOperationDO> operationMap) {
        ProcessingInfomationOperationRespVO resp = BeanUtils.toBean(relation, ProcessingInfomationOperationRespVO.class);
        ProcessingOperationDO previous = operationMap.get(relation.getPreviousOperationId());
        if (previous != null) {
            resp.setPreviousOperationCode(previous.getCode());
            resp.setPreviousOperationName(previous.getName());
        }
        ProcessingOperationDO next = operationMap.get(relation.getNextOperationId());
        if (next != null) {
            resp.setNextOperationCode(next.getCode());
            resp.setNextOperationName(next.getName());
        }
        return resp;
    }

}