package com.cf.imes.module.executor.service.plate;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.es.core.service.ESDocumentService;
import com.cf.imes.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.executor.controller.admin.goods.vo.GoodsSaveReqVO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.executor.dal.dataobject.ordermodel.OrderModelDO;
import com.cf.imes.module.executor.dal.dataobject.processStepItem.OrderProcessStepItemDO;
import com.cf.imes.module.executor.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.executor.dal.mysql.processStepItem.ProcessStepItemMapper;
import com.cf.imes.module.executor.util.RandomUtils;
import com.cf.imes.module.system.enums.ErrorCodeConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

import com.cf.imes.module.executor.controller.admin.plate.vo.*;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.object.BeanUtils;

import com.cf.imes.module.executor.dal.mysql.plate.PlateMapper;

import static com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getUserOrganId;
import static com.cf.imes.module.executor.service.optimizeplan.OptimizePlanService.ORDER_PLATE_MODEL;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PLATE_NOT_EXISTS;

/**
 * 生产单板件 Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
@Slf4j
public class PlateServiceImpl implements PlateService {

    @Resource
    private PlateMapper plateMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private ElasticsearchClient elasticsearchClient;

    @Resource
    private ProcessStepItemMapper processStepItemMapper;

    @Override
    public Long createPlate(PlateSaveReqVO createReqVO) {
        // 插入
        PlateDO plate = BeanUtils.toBean(createReqVO, PlateDO.class);
        plateMapper.insert(plate);
        // 返回
        return plate.getId();
    }

    @Override
    public void updatePlate(PlateSaveReqVO updateReqVO) {
        // 校验存在
        validatePlateExists(updateReqVO.getId());
        // 更新
        PlateDO updateObj = BeanUtils.toBean(updateReqVO, PlateDO.class);
        plateMapper.updateById(updateObj);
    }

    @Override
    public void deletePlate(Long id) {
        // 校验存在
        validatePlateExists(id);
        // 删除
        plateMapper.deleteById(id);
    }

    private void validatePlateExists(Long id) {
        if (plateMapper.selectById(id) == null) {
            throw exception(PLATE_NOT_EXISTS);
        }
    }

    @Override
    public List<PlateRespVO> getPlate(PlateDetailReqVO reqVO) {

        // 获取到当前登录用户的信息
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();

        // 查询生产单下的大板,余料板，排单状态的信息
        PlateDetailRespVO plateDetailRespVO = orderItemMapper.selectPlateNumList(reqVO.getOrderId(),getUserOrganId());
//        PlateDetailRespVO plateDetailRespVO = plateMapper.selectPlateNumList(reqVO);
        plateDetailRespVO.setCompanyId(loginUser.getId());

//        PlateRespVO plateRespVO = BeanUtil.toBean(plateDetailRespVO, PlateRespVO.class);

        // 查询生产单下的板材详细信息
        List<PlateRespVO> plateRespVOS = orderItemMapper.selectPlateList(reqVO,getUserOrganId());

//        List<PlateRespVO> plateRespVOS2 = plateRespVOS
//                .stream()
//                .map(item -> BeanUtil.toBean(plateDetailRespVO, PlateRespVO.class))
//                .collect(Collectors.toList());

        // 将大板等信息循环插入
        for (PlateRespVO respVO : plateRespVOS) {
            respVO.setCompanyId(plateDetailRespVO.getCompanyId());
            respVO.setPlanStatus(plateDetailRespVO.getPlanStatus());
            respVO.setBigPlateNum(plateDetailRespVO.getBigPlateNum());
            respVO.setRemainPlateNum(plateDetailRespVO.getRemainPlateNum());
        }

        return plateRespVOS;


    }

    @Override
    public PageResult<PlateDO> getPlatePage(PlatePageReqVO pageReqVO) {
        return plateMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public PlateImportRespVO importPlatesList(List<PlateSaveReqVO> importPlates, Long orderId) {
        if (CollUtil.isEmpty(importPlates)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.RAW_GOODS_IMPORT_LIST_IS_EMPTY);
        }
        PlateImportRespVO respVO = PlateImportRespVO.builder().createPlates(new ArrayList<PlateSaveReqVO>())
                .updatePlates(new ArrayList<>()).failurePlates(new LinkedHashMap<>()).build();
        importPlates.forEach(plateSaveReqVO -> {
            try {
//                改成plateMapper.insertBatch()
                Long id = (long) plateMapper.insert(BeanUtils.toBean(plateSaveReqVO, PlateDO.class)
                        .setOrderId(orderId));
                respVO.getCreatePlates().add(plateSaveReqVO);
            } catch (ServiceException ex) {
                respVO.getFailurePlates().put(plateSaveReqVO.getName(), ex.getMessage());
            }
        });
        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePlates(Set<Long> ids) {
        plateMapper.deleteBatchIds(ids);
    }

    @Override
    public List<PlateDO> getPlatesByOrderId(Long orderId) {
        List<PlateDO> plates = plateMapper.selectList(new LambdaQueryWrapper<PlateDO>().eq(PlateDO::getOrderId, orderId));
        return plates;
    }

    @Override
    public PageResult<PlateRespVO> getPlatePageByTerms(PlateTermsPageReqVO pageReqVO) {
        PageDTO<PlateRespVO> page = new PageDTO<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<PlateRespVO> pageRes = plateMapper.selectProductList(page, pageReqVO.getOrderId(), pageReqVO.getRoomId(), pageReqVO.getBodyId(),getUserOrganId());
        return new PageResult<PlateRespVO>(pageRes.getRecords(), pageRes.getTotal());
    }

    @Override
    public void updatePlateByRawGoodsId(List<GoodsSaveReqVO> createReqVOS) {
        // 根据生产单id和goods_id查到数据，再更新goods_id
        createReqVOS.forEach(createReqVO -> {
//            plateMapper.update(null,
//                    new LambdaQueryWrapper<PlateDO>()
//                            .eq(PlateDO::getGoodsId, createReqVO.getRawGoodsId())
//                            .eq(PlateDO::getOrderId, createReqVO.getOrderId())
//                            .set(PlateDO::getGoodsId, createReqVO.getGoodsId()
//            );

        });

    }


    @SneakyThrows
    @Override
    public List<BodyPlateDetailVO> getPlateModelByPlateId(List<Long> bodyIds)  {
        List<BodyPlateIdDTO> list = plateMapper.selectJoinList(BodyPlateIdDTO.class, new MPJLambdaWrapperX<PlateDO>()
                .selectAs(PlateDO::getId, "plateId")
                .leftJoin(OrderItemDO.class, OrderItemDO::getPlateId, PlateDO::getId)
                .eq(OrderItemDO::getOrganId,getUserOrganId())
                .in(OrderItemDO::getBodyId, bodyIds)
                .select(OrderItemDO::getBodyId)
        );
        List<Long> plateIds = list.stream().map(BodyPlateIdDTO::getPlateId).collect(Collectors.toList());
        List<OrderModelDO> orderModelDOS = buildRespByPlateIds(plateIds, ORDER_PLATE_MODEL);
        Map<Long, List<OrderModelDO>> map = orderModelDOS.stream().collect(Collectors.groupingBy(e -> {
            return list.stream().filter(f -> Objects.equals(f.getPlateId(), e.getPlateId())).map(BodyPlateIdDTO::getBodyId).findAny().orElse(null);
        }));

        List<BodyPlateDetailVO> bodyPlateDetailVOS = new ArrayList<>();
        List<List<List<Object>>> data = new ArrayList<>();
        map.entrySet().forEach(e->{
                bodyPlateDetailVOS.add(BodyPlateDetailVO.builder()
                        .orderModelList(e.getValue())
                        .bodyId(e.getKey())
                        .build()
                );
        });
        return bodyPlateDetailVOS;
    }








    private List<OrderModelDO> buildRespByPlateIds(Collection<Long> plateIds, String index) {
        //


//        // 使用Stream API将 Collection<Long> 转换成 Collection<String>
//        Collection<String> stringPlateIds = plateIds.stream()
//                .map(String::valueOf) // 将Long类型的元素转换成String类型
//                .collect(Collectors.toList()); // 收集到一个新的List中

        List<FieldValue> fieldValues = plateIds.stream().map(FieldValue::of).toList();
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index);
        builder.query(q -> q.terms(b -> b.field("plateId").terms(e->e.value(fieldValues))));
        builder.size(plateIds.size());
        try {
            SearchResponse<OrderModelDO> search = elasticsearchClient.search(builder.build(), OrderModelDO.class);
            List<Hit<OrderModelDO>> hits = search.hits().hits();
            if (CollectionUtil.isNotEmpty(hits)) {
                return hits.stream().map(Hit::source).collect(Collectors.toList());
            }
            return new ArrayList<>();
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new ServiceException(INTERNAL_SERVER_ERROR);
        }
    }


}