package com.gci.boot.modules.vehicles.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.gci.boot.annotation.Query.handle.QueryGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.vehicles.entity.TbConsumablesTemplate;
import com.gci.boot.modules.vehicles.entity.TbConsumablesTemplateOutPart;
import com.gci.boot.modules.vehicles.entity.TbConsumablesTemplatePart;
import com.gci.boot.modules.vehicles.mapper.TbConsumablesTemplateOutPartMapper;
import com.gci.boot.modules.vehicles.mapper.TbConsumablesTemplatePartMapper;
import com.gci.boot.modules.vehicles.service.ITbConsumablesTemplateOutPartService;
import com.gci.boot.modules.vehicles.service.ITbConsumablesTemplatePartService;
import com.gci.boot.modules.vehicles.service.ITbConsumablesTemplateService;

import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

/**
 * <p>
 * 耗材详情 服务实现类
 * </p>
 *
 * @author 2464
 * @since 2023-09-12
 */
@Service
public class TbConsumablesTemplatePartServiceImpl
    extends ServiceImpl<TbConsumablesTemplatePartMapper, TbConsumablesTemplatePart>
    implements ITbConsumablesTemplatePartService {

    @Autowired
    @Lazy
    private ITbConsumablesTemplateService templateService;
    @Autowired
    private ITbConsumablesTemplateOutPartService outPartService;
    @Autowired
    private TbConsumablesTemplateOutPartMapper outPartMapper;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void init() {
        List<TbConsumablesTemplate> list = templateService.list();
        List<TbConsumablesTemplatePart> list1 = list();
        for (TbConsumablesTemplatePart part : list1) {
            part.setRemainingQuantity(part.getQuantity());
            for (TbConsumablesTemplate tbConsumablesTemplate : list) {
                if (StrUtil.isNotBlank(part.getTemplateId())) {
                    if (part.getTemplateId().equals(tbConsumablesTemplate.getId())) {
                        part.setProjectId(tbConsumablesTemplate.getProjectId());
                    }
                }
            }
        }
        updateBatchById(list1);
    }

    @Override
    public IPage<TbConsumablesTemplatePart> pageBuild(Page<TbConsumablesTemplatePart> page,
        LambdaQueryWrapper<TbConsumablesTemplatePart> lambdaQueryWrapper, boolean onlyHadQuantity) {
        if (onlyHadQuantity) {
            lambdaQueryWrapper.ge(TbConsumablesTemplatePart::getRemainingQuantity, 0)
                .orderByAsc(TbConsumablesTemplatePart::getStorageTime);
        }
        Page<TbConsumablesTemplatePart> partPage = page(page, lambdaQueryWrapper);
        List<TbConsumablesTemplatePart> records = partPage.getRecords();

        // 查找对应出库记录
        List<String> collect = records.stream().map(TbConsumablesTemplatePart::getId).collect(Collectors.toList());
        List<TbConsumablesTemplateOutPart> outPartList = new ArrayList<>();
        if (!collect.isEmpty()) {
            outPartList = outPartService.list(new LambdaQueryWrapper<TbConsumablesTemplateOutPart>()
                .in(TbConsumablesTemplateOutPart::getPartId, collect)
                .orderByDesc(TbConsumablesTemplateOutPart::getOutStorageTime));
        }

        Map<String, List<TbConsumablesTemplateOutPart>> collect1 =
            outPartList.stream().collect(Collectors.groupingBy(TbConsumablesTemplateOutPart::getPartId));
        for (TbConsumablesTemplatePart record : records) {
            List<TbConsumablesTemplateOutPart> tbConsumablesTemplateOutParts = collect1.get(record.getId());
            Integer count = 0;
            if (ObjectUtil.isNotEmpty(tbConsumablesTemplateOutParts)) {
                // 赋值补充参数
                for (TbConsumablesTemplateOutPart tbConsumablesTemplateOutPart : tbConsumablesTemplateOutParts) {
                    tbConsumablesTemplateOutPart.setName(record.getName());
                    tbConsumablesTemplateOutPart.setUnits(record.getUnits());
                    tbConsumablesTemplateOutPart.setSpecification(record.getSpecification());
                    tbConsumablesTemplateOutPart.setProjectId(record.getProjectId());
                    if (tbConsumablesTemplateOutPart.getOutQuantity() != null) {
                        count = count + tbConsumablesTemplateOutPart.getOutQuantity();
                    }
                }
                record.setOutQuantityCount(count);
                record.setOutPartList(tbConsumablesTemplateOutParts);
            }
        }
        return partPage;
    }

    @Override
    public void inStorage(List<TbConsumablesTemplatePart> partList) {

        List<TbConsumablesTemplatePart> list =
            list(new LambdaQueryWrapper<TbConsumablesTemplatePart>().in(TbConsumablesTemplatePart::getProjectId,
                partList.stream().map(TbConsumablesTemplatePart::getProjectId).collect(Collectors.toList())));
        for (TbConsumablesTemplatePart part : partList) {
            for (TbConsumablesTemplatePart t : list) {
                if (part.getProjectId().equals(t.getProjectId()) && part.getName().equals(t.getName())
                    && part.getStorageTime().equals(t.getStorageTime())
                    && part.getSpecification().equals(t.getSpecification())
                    && part.getSupplier().equals(t.getSupplier())) {
                    throw new GciBootException("同一项目内相同耗材出库日期不能重复！");
                }
            }
        }

        List<String> copyPartList = new ArrayList<>();
        StrBuilder strBuilder = new StrBuilder();
        for (int i = 0; i < partList.size(); i++) {
            TbConsumablesTemplatePart part = partList.get(i);
            String s = part.getName() + part.getStorageTime();
            if (copyPartList.contains(s)) {
                strBuilder.append(String.valueOf(i + 1)).append("行与列表内数据重复！");
            }
            copyPartList.add(s);
            part.setRemainingQuantity(part.getQuantity());
        }
        if (!strBuilder.isEmpty()) {
            throw new GciBootException(strBuilder.toString());
        } else {
            saveBatch(partList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void outStorage(List<TbConsumablesTemplateOutPart> partList) {
        Map<String, List<TbConsumablesTemplateOutPart>> collect =
            partList.stream().collect(Collectors.groupingBy(TbConsumablesTemplateOutPart::getPartId));
        Set<String> strings = collect.keySet();
        // 需要先和测试环境数据进行重复校验
        List<TbConsumablesTemplateOutPart> list1 =
            outPartService.list(new LambdaQueryWrapper<TbConsumablesTemplateOutPart>()
                .in(TbConsumablesTemplateOutPart::getPartId, strings));
        list1.addAll(partList);
        Map<String,
            Long> collect1 = list1.stream()
                .collect(Collectors.groupingBy(p -> p.getName() + "_" + p.getPartId() + "_" + p.getOutStorageTime()
                    + "_" + p.getSupplier() + "_" + p.getSupplier(), Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue() > 1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        if (!collect1.isEmpty()) {
            throw new GciBootException("同一项目内相同耗材出库日期不能重复！");
        }
        List<TbConsumablesTemplatePart> list =
            list(new LambdaQueryWrapper<TbConsumablesTemplatePart>().in(TbConsumablesTemplatePart::getId, strings));
        if (list.size() != strings.size()) {
            throw new GciBootException("存在非法id!");
        }
        for (TbConsumablesTemplatePart inPart : list) {
            List<TbConsumablesTemplateOutPart> tbConsumablesTemplateOutParts = collect.get(inPart.getId());
            if (ObjectUtil.isNotEmpty(tbConsumablesTemplateOutParts)) {
                for (TbConsumablesTemplateOutPart tbConsumablesTemplateOutPart : tbConsumablesTemplateOutParts) {
                    if (tbConsumablesTemplateOutPart.getOutStorageTime().before(inPart.getStorageTime())) {
                        throw new GciBootException("出库时间不能大于入库时间!");
                    }
                }
            }
        }
        ArrayList<TbConsumablesTemplatePart> needUpdate = new ArrayList<>();
        ArrayList<TbConsumablesTemplateOutPart> needOutAdd = new ArrayList<>();
        ArrayList<TbConsumablesTemplateOutPart> needOutUpdate = new ArrayList<>();
        checkAndBuild(collect, list, needUpdate, needOutAdd, needOutUpdate);
        updateBatchById(needUpdate);
        outPartService.saveBatch(needOutAdd);
    }

    private void checkAndBuild(Map<String, List<TbConsumablesTemplateOutPart>> collect,
        List<TbConsumablesTemplatePart> list, ArrayList<TbConsumablesTemplatePart> needUpdate,
        ArrayList<TbConsumablesTemplateOutPart> needOutAdd, ArrayList<TbConsumablesTemplateOutPart> needOutUpdate) {
        for (Map.Entry<String, List<TbConsumablesTemplateOutPart>> stringListEntry : collect.entrySet()) {
            String key = stringListEntry.getKey();
            List<TbConsumablesTemplateOutPart> value = stringListEntry.getValue();
            TbConsumablesTemplatePart part = list.stream().filter(l -> l.getId().equals(key)).findFirst().get();
            // 名字和日期校验
            Map<String,
                Long> collect1 = value.stream()
                    .collect(Collectors.groupingBy(p -> p.getName() + "_" + p.getPartId() + "_" + p.getOutStorageTime()
                        + "_" + p.getSupplier() + "_" + p.getSupplier(), Collectors.counting()))
                    .entrySet().stream().filter(e -> e.getValue() > 1)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            if (!collect1.isEmpty()) {
                throw new GciBootException("同一项目内相同耗材出库日期不能重复！");
            }

            // 数量校验
            Integer totalOut = value.stream().mapToInt(TbConsumablesTemplateOutPart::getOutQuantity).sum();
            int residue = part.getRemainingQuantity() - totalOut;
            part.setRemainingQuantity(residue);
            if (residue < 0) {
                throw new GciBootException(part.getName() + "剩余库存不足!");
            } else {
                part.setRemainingQuantity(residue);
                needUpdate.add(part);
                for (TbConsumablesTemplateOutPart tbConsumablesTemplateOutPart : value) {
                    if (StrUtil.isBlank(tbConsumablesTemplateOutPart.getId())) {
                        needOutAdd.add(tbConsumablesTemplateOutPart);
                    } else {
                        needOutUpdate.add(tbConsumablesTemplateOutPart);
                    }
                }
            }

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inAndOutStorage(TbConsumablesTemplatePart part) {
        // 因为页面上既可以编辑入库信息又可以编辑出库信息
        // 所有只需要以前端数据为主进行校验
        // 前端传过来的数据
        List<TbConsumablesTemplateOutPart> outPartList = part.getOutPartList();

        Map<String, List<TbConsumablesTemplateOutPart>> collect =
            outPartList.stream().collect(Collectors.groupingBy(TbConsumablesTemplateOutPart::getPartId));
        Set<String> strings = collect.keySet();
        List<TbConsumablesTemplatePart> list =
            list(new LambdaQueryWrapper<TbConsumablesTemplatePart>().in(TbConsumablesTemplatePart::getId, strings));
        if (list.size() != strings.size() || list.size() > 1) {
            throw new GciBootException("存在非法id!");
        }
        // 以前端数据为主
        list.clear();
        list.add(part);
        for (TbConsumablesTemplatePart inPart : list) {
            List<TbConsumablesTemplateOutPart> tbConsumablesTemplateOutParts = collect.get(inPart.getId());
            if (ObjectUtil.isNotEmpty(tbConsumablesTemplateOutParts)) {
                for (TbConsumablesTemplateOutPart tbConsumablesTemplateOutPart : tbConsumablesTemplateOutParts) {
                    if (tbConsumablesTemplateOutPart.getOutStorageTime().before(inPart.getStorageTime())) {
                        throw new GciBootException("出库时间不能大于入库时间!");
                    }
                }
            }
        }
        part.setRemainingQuantity(part.getQuantity());
        ArrayList<TbConsumablesTemplatePart> needUpdate = new ArrayList<>();
        ArrayList<TbConsumablesTemplateOutPart> needOutAdd = new ArrayList<>();
        ArrayList<TbConsumablesTemplateOutPart> needOutUpdate = new ArrayList<>();
        checkAndBuild(collect, list, needUpdate, needOutAdd, needOutUpdate);
        updateBatchById(needUpdate);
        outPartService.updateBatchById(needOutUpdate);
        outPartService.saveBatch(needOutAdd);
    }

}
