package com.ruoyi.inventory.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.SimpleFormatter;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.asset.domain.TbAssetInformation;
import com.ruoyi.asset.domain.TbLocation;
import com.ruoyi.asset.mapper.TbAssetInformationMapper;
import com.ruoyi.asset.mapper.TbLocationMapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.inventory.domain.TagInfo;
import com.ruoyi.inventory.domain.TbInventoryDetail;
import com.ruoyi.inventory.domain.dto.TakeStockDTO;
import com.ruoyi.inventory.domain.dto.TbAssetInventoryDTO;
import com.ruoyi.inventory.mapper.TbInventoryDetailMapper;
import com.ruoyi.utils.IDUtil;
import com.ruoyi.utils.RecursionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.inventory.mapper.TbAssetInventoryMapper;
import com.ruoyi.inventory.domain.TbAssetInventory;
import com.ruoyi.inventory.service.ITbAssetInventoryService;

import javax.annotation.Resource;

/**
 * 资产盘点记录Service业务层处理
 * 
 * @author ydl
 * @date 2023-06-01
 */
@Service
public class TbAssetInventoryServiceImpl implements ITbAssetInventoryService
{
    @Autowired
    private TbAssetInventoryMapper tbAssetInventoryMapper;

    @Autowired
    private TbAssetInformationMapper informationMapper;

    @Autowired
    private TbInventoryDetailMapper tbInventoryDetailMapper;

    @Autowired
    private TbLocationMapper locationMapper;

    /**
     * 查询资产盘点记录
     * 
     * @param id 资产盘点记录主键
     * @return 资产盘点记录
     */
    @Override
    public TbAssetInventory selectTbAssetInventoryById(Long id)
    {
        TbAssetInventory tbAssetInventory = tbAssetInventoryMapper.selectTbAssetInventoryById(id);
        setLocationName(tbAssetInventory);

        return tbAssetInventory;
    }

    private void setLocationName(TbAssetInventory tbAssetInventory) {
        String inventoryLocation = tbAssetInventory.getInventoryLocation();
        String[] strLocationIds = inventoryLocation.split(",");
        List<TbLocation> tbLocations = locationMapper.selectTbLocationByIds(List.of(strLocationIds));
        String locationName = Arrays.toString(tbLocations.stream().map(TbLocation::getName).toArray());
        tbAssetInventory.setInventoryLocationName(locationName);
    }


    @Override
    public TbAssetInventory selectTbAssetInventoryByNum(String num) {
        TbAssetInventory tbAssetInventory = tbAssetInventoryMapper.selectTbAssetInventoryByNumber(num);
        setLocationName(tbAssetInventory);
        return tbAssetInventory;
    }

    /**
     * 查询资产盘点记录列表
     * 
     * @param tbAssetInventory 资产盘点记录
     * @return 资产盘点记录
     */
    @Override
    public List<TbAssetInventory> selectTbAssetInventoryList(TbAssetInventory tbAssetInventory)
    {
        return tbAssetInventoryMapper.selectTbAssetInventoryList(tbAssetInventory);
    }

    /**
     * 新增资产盘点记录
     * 
     * @param tbAssetInventory 资产盘点记录
     * @return 结果
     */
    @Override
    public int insertTbAssetInventory(TbAssetInventory tbAssetInventory)
    {
        String orderNumber = IDUtil.getUUID1();
        tbAssetInventory.setOrderNumber(orderNumber);

        Integer recordStatus = tbAssetInventory.getRecordStatus();
        if (recordStatus > 0) {
            tbAssetInventory.setInventoryStatus(1);
        } else {
            tbAssetInventory.setInventoryStatus(0);
        }

        String inventoryLocation = tbAssetInventory.getInventoryLocation();
        String[] locationIds = inventoryLocation.split(",");
        Set<String> locationNumberSet = new HashSet<>();
        for (String locationId : locationIds) {
            List<String> locationNumberList = locationMapper.selectChildTbLocationById(Long.valueOf(locationId));
            locationNumberSet.addAll(locationNumberList);
        }
        List<TbAssetInformation> tbAssetInformationList = informationMapper.selectAssetInformationByLocations(locationNumberSet);

        List<TbInventoryDetail> tbInventoryDetails = new ArrayList<>();
        for (TbAssetInformation tbAssetInformation : tbAssetInformationList) {
            // 未盘点
            TbInventoryDetail uncounted = TbInventoryDetail.uncounted(orderNumber, tbAssetInformation);
            tbInventoryDetails.add(uncounted);
        }

        int insertTbAssetInventory = tbAssetInventoryMapper.insertTbAssetInventory(tbAssetInventory);
        if (insertTbAssetInventory == 0) {
            return 0;
        }

        for (TbInventoryDetail tbInventoryDetail : tbInventoryDetails) {
            tbInventoryDetailMapper.insertTbInventoryDetail(tbInventoryDetail);
        }

        return 1;
    }

    /**
     * 手持机盘点
     *
     * @param takeStockDTOList
     * @return
     */
    @Override
    public int handheldInventory(List<TakeStockDTO> takeStockDTOList) {
        int result = 0;
        for (TakeStockDTO takeStockDTO : takeStockDTOList) {
            // 获取单据编码
            String orderNumber = takeStockDTO.getOrderNumber();
            // 获取手持机的epc
            Set<String> epcSet = takeStockDTO.getAssetList()
                    .stream()
                    .map(tagInfo -> {
                        String epc = tagInfo.getEpc();
                        // 删除字符串中前导的零
                        epc = epc.replaceFirst("^0+", "");
                        return epc;
                    })
                    .collect(Collectors.toSet());
            if (StrUtil.isNotBlank(orderNumber)) { // 存在盘点计划
                TbAssetInventory tbAssetInventory = tbAssetInventoryMapper.selectTbAssetInventoryByNumber(orderNumber);
                if (tbAssetInventory == null) {
                    continue;
                }

                Integer stockResult = startStock(tbAssetInventory,  epcSet);
                if (stockResult > 0) {
                    result++;
                }
            } else { // 未存在盘点计划
                // 获取盘点位置编码
                String inventoryLocation = takeStockDTO.getInventoryLocation();
                List<String> locationNumbers = List.of(inventoryLocation.split(","));

                // 根据编号获取有效位置ID
                List<Long> locationIds = locationMapper.selectTbLocationIdByNumbers(locationNumbers);
                if (locationIds.isEmpty()) {
                    continue;
                }

                TbAssetInventory inventory = new TbAssetInventory();
                Date now = new Date();
                String nowDateTime = DateUtil.format(now, "yyyy年MM月dd日 HH:mm:ss");
                inventory.setName(nowDateTime + "临时盘点任务");
                inventory.setInventoryDepartment("100");
                inventory.setInventoryBy("admin");
                inventory.setInventoryDate(now);

                StringBuilder locationStrIds = new StringBuilder();
                for (int i = 0; i < locationIds.size(); i++) {
                    locationStrIds.append(locationIds.get(i));
                    if (i < locationIds.size() - 1) {
                        locationStrIds.append(",");
                    }
                }
                inventory.setInventoryLocation(locationStrIds.toString());
                inventory.setRecordStatus(1);

                // 新增盘点计划
                int insertResult = insertTbAssetInventory(inventory);
                if (insertResult < 1) { // 新增失败
                    continue;
                }

                // 获取单点单号
                String newOrderNumber = inventory.getOrderNumber();
                // 获取盘点计划
                TbAssetInventory tbAssetInventory = tbAssetInventoryMapper.selectTbAssetInventoryByNumber(newOrderNumber);

                Integer stockResult = startStock(tbAssetInventory, epcSet);
                if (stockResult > 0) {
                    result++;
                }
            }

        }
        return result > 0 ? 1 : 0;
    }

    /**
     * 开始盘点
     *
     * @param tbAssetInventory 盘点计划信息
     * @param epcSet 盘点epc集合
     */
    private Integer startStock(TbAssetInventory tbAssetInventory, Set<String> epcSet) {
        // 获取盘点单号
        String orderNumber = tbAssetInventory.getOrderNumber();

        int result = 0;
        // 设置盘点状态：盘点完毕
        tbAssetInventory.setInventoryStatus(2);
        // 记录已盘点epc
        Set<String> epcRecord = new HashSet<>();

        // 根据盘点单号获取盘点资产详细
        List<TbInventoryDetail> tbInventoryDetails = tbInventoryDetailMapper.selectTbInventoryDetailByOrderNumber(orderNumber);
        for (TbInventoryDetail tbInventoryDetail : tbInventoryDetails) {
            // 获取资产元数据
            String inventoryMetadata = tbInventoryDetail.getInventoryMetadata();
            // 将元数据转换为资产信息
            TbAssetInformation assetInformation = JSONUtil.toBean(inventoryMetadata, TbAssetInformation.class);
            // 判断是否盘点到该epc
            boolean flag = epcSet.stream().anyMatch(epc -> epc.equals(assetInformation.getEpc()));
            if (flag) {
                // 设置盘点更新状态：已盘点
                tbInventoryDetail.setIsUpdateData(1);
                int update = tbInventoryDetailMapper.updateTbInventoryDetail(tbInventoryDetail);
                if (update > 0) {
                    // 新增已盘点epc
                    epcRecord.add(assetInformation.getEpc());
                    // 删除已盘点epc
                    epcSet.remove(assetInformation.getEpc());
                    if (result < 1) {
                        result = 1;
                    }
                }
            }
        }

        // 统计未盘点
        int uncountedCount = tbInventoryDetailMapper.countUncounted(orderNumber);

        // 获取盘点位置
        String inventoryLocation = tbAssetInventory.getInventoryLocation();
        List<Long> locationIds = Arrays.stream(inventoryLocation.split(",")).map(Long::valueOf).collect(Collectors.toList());
        List<String> locationNumbers = locationMapper.selectChildTbLocationByIds(locationIds);

        // 根据盘点位置获取位置下的资产信息
        List<TbAssetInformation> locationAssetInformationList = informationMapper.selectAssetInformationByLocations(locationNumbers);

        if (!locationAssetInformationList.isEmpty()) {
            // 获取该位置下的全部资产epc
            Set<String> newEpcSet = locationAssetInformationList.stream().map(TbAssetInformation::getEpc).collect(Collectors.toSet());
            // 删除已盘点epc
            newEpcSet.removeAll(epcRecord);

            if (!newEpcSet.isEmpty()) {
                // 获取存在该位置且未盘点资产信息
                List<TbAssetInformation> newEpcAssetInformationList = locationAssetInformationList.stream().map(tbAssetInformation -> {
                    for (String newEpc : newEpcSet) {
                        if (tbAssetInformation.getEpc().equals(newEpc)) {
                            return tbAssetInformation;
                        }
                    }
                    return null;
                }).collect(Collectors.toList());

                for (TbAssetInformation tbAssetInformation : newEpcAssetInformationList) {
                    if (tbAssetInformation == null) {
                        continue;
                    }
                    String newEpc = tbAssetInformation.getEpc();
                    // 判断是否盘点到该epc
                    boolean flag = epcSet.stream().anyMatch(epc -> epc.equals(newEpc));
                    if (flag) {
                        // 已盘点资产详细
                        TbInventoryDetail counted = TbInventoryDetail.counted(orderNumber, tbAssetInformation);
                        int inserted = tbInventoryDetailMapper.insertTbInventoryDetail(counted);
                        if (inserted > 0) {
                            // 新增已盘点epc
                            epcRecord.add(newEpc);
                            // 删除已盘点epc
                            epcSet.remove(newEpc);
                            if (result < 1) {
                                result = 1;
                            }
                        }
                    }
                }
            }
        }

        // 根据未盘点资产epc获取资产信息
        List<TbAssetInformation> tbAssetInformationList = informationMapper.selectTbAssetInformationByEpcList(epcSet);
        for (TbAssetInformation tbAssetInformation : tbAssetInformationList) {
            TbInventoryDetail tbInventoryDetail = TbInventoryDetail.errCounted(orderNumber, tbAssetInformation);
            tbInventoryDetailMapper.insertTbInventoryDetail(tbInventoryDetail);
        }

        if (uncountedCount > 0) { // 未盘点统计大于0时 盘亏
            tbAssetInventory.setInventoryResult(2);
        } else if (epcRecord.size() > tbInventoryDetails.size()) { // 未盘点统计0，且实际已盘点数大于计划盘点数 盘盈
            tbAssetInventory.setInventoryResult(1);
        } else { // 未盘点统计0，且实际已盘点数等于计划盘点数 正常
            tbAssetInventory.setInventoryResult(3);
        }

        tbAssetInventoryMapper.updateTbAssetInventory(tbAssetInventory);
        return result;
    }

    /**
     * 修改资产盘点记录
     * 
     * @param tbAssetInventory 资产盘点记录
     * @return 结果
     */
    @Override
    public int updateTbAssetInventory(TbAssetInventory tbAssetInventory)
    {
        Integer recordStatus = tbAssetInventory.getRecordStatus();
        if (recordStatus > 0) {
            tbAssetInventory.setInventoryStatus(1);
        } else {
            tbAssetInventory.setInventoryStatus(0);
        }
        return tbAssetInventoryMapper.updateTbAssetInventory(tbAssetInventory);
    }

    /**
     * 批量删除资产盘点记录
     * 
     * @param ids 需要删除的资产盘点记录主键
     * @return 结果
     */
    @Override
    public int deleteTbAssetInventoryByIds(Long[] ids)
    {
        List<String> orderNumbers = tbAssetInventoryMapper.selectOrderNumberByIds(List.of(ids));
        tbInventoryDetailMapper.deleteTbInventoryDetailByOrderNumbers(orderNumbers);
        return tbAssetInventoryMapper.deleteTbAssetInventoryByIds(ids);
    }

    /**
     * 删除资产盘点记录信息
     * 
     * @param id 资产盘点记录主键
     * @return 结果
     */
    @Override
    public int deleteTbAssetInventoryById(Long id)
    {
        TbAssetInventory tbAssetInventory = tbAssetInventoryMapper.selectTbAssetInventoryById(id);
        if (tbAssetInventory == null) {
            return 0;
        }
        String orderNumber = tbAssetInventory.getOrderNumber();
        tbInventoryDetailMapper.deleteTbInventoryDetailByOrderNumbers(Collections.singletonList(orderNumber));
        return tbAssetInventoryMapper.deleteTbAssetInventoryById(id);
    }

    @Override
    public List<TbAssetInventoryDTO> selectTbAssetInventoryDTOList(TbAssetInventoryDTO dto) {
        List<TbAssetInventoryDTO> tbAssetInventoryDTOS = tbAssetInventoryMapper.selectTbAssetInventoryDTOList(dto);
        for (TbAssetInventoryDTO tbAssetInventoryDTO : tbAssetInventoryDTOS) {
            setLocationNameDTO(tbAssetInventoryDTO);
        }
        return tbAssetInventoryDTOS;
    }

    private void setLocationNameDTO(TbAssetInventoryDTO tbAssetInventoryDTO) {
        String inventoryLocation = tbAssetInventoryDTO.getInventoryLocation();
        String[] strLocationIds = inventoryLocation.split(",");
        List<TbLocation> tbLocations = locationMapper.selectTbLocationByIds(List.of(strLocationIds));
        String locationName = Arrays.toString(tbLocations.stream().map(TbLocation::getName).toArray());
        tbAssetInventoryDTO.setInventoryLocationName(locationName);
    }

    // 旧手持机盘点
    public int addByTakeStock(List<TakeStockDTO> _dto){
        int result = 0;
        for (TakeStockDTO dto : _dto) {
            //解析实体
            List<TagInfo> list = dto.getAssetList();
            String location = dto.getInventoryLocation();
            String orderNumber = dto.getOrderNumber();
            //提取epc rfid
            ArrayList<String> epcList = new ArrayList<>();
            for (TagInfo tagInfo : list) {
                String epc = tagInfo.getEpc();
                // 删除字符串中前导的零
                epc = epc.replaceFirst("^0+", "");
                epcList.add(epc);
            }
            //根据位置获取包含自身及子位置,递归
            List<String> locations = new RecursionUtil().getNumberWithChildren(locationMapper, location);
            //获取所在位置内的资产
            // List<String> rfidList = informationMapper.selectNumberByLocations(locations);
            List<TbAssetInformation> informationList = informationMapper.selectAssetInformationByLocations(locations);
            List<String> rfidList = informationList.stream().map(TbAssetInformation::getEpc).collect(Collectors.toList());

            //对比盘点
            List<String> intersection = new ArrayList<>(rfidList);
            intersection.retainAll(epcList);
            if (intersection.size() < rfidList.size()) {
                //盘亏
                if (!orderNumber.isEmpty()) {
                    result = takeStock(orderNumber, epcList, 2);
                } else {
                    result = takeStock2(location, 2, epcList);
                }
            } else if (list.size() > intersection.size()) {
                //盘盈
                if (!orderNumber.isEmpty()) {
                    result = takeStock(orderNumber, epcList, 1);
                } else {
                    result = takeStock2(location, 1, epcList);
                }
            } else if (intersection.size() == rfidList.size()) {
                //正常
                if (!orderNumber.isEmpty()) {
                    result = takeStock(orderNumber, epcList, 3);
                } else {
                    result = takeStock2(location, 3, epcList);
                }
            } else {
                result = 0;
            }
        }
        return result;
    }

    // 旧手持机盘点
    private int takeStock(String orderNumber, List<String> list, Integer result){
        TbAssetInventory inventory = tbAssetInventoryMapper.selectTbAssetInventoryByNumber(orderNumber);
        if (inventory.getRecordStatus() == 1) {
            //插入盘点
            inventory.setInventoryStatus(2);
            inventory.setInventoryResult(result);
            //插入明细
            setDetail(orderNumber, list);
            return updateTbAssetInventory(inventory);
        }else {
            return 0;
        }
    }

    // 旧手持机盘点
    private int takeStock2(String location, Integer result, List<String> list){
        TbAssetInventory inventory = new TbAssetInventory();
        inventory.setInventoryStatus(2);
        inventory.setInventoryResult(result);
        inventory.setRecordStatus(1);
        inventory.setInventoryLocation(location);
        inventory.setInventoryDate(new Date());
        SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd HH:mm:ss");
        String format = formatter.format(new Date());
        inventory.setName("线下自测"+format);
        int i = insertTbAssetInventory(inventory);
        if(i < 1){
            throw new ServiceException("生成盘点记录失败");
        }
        String orderNumber = inventory.getOrderNumber();
        //插入盘点明细
        setDetail(orderNumber, list);
        return 1;
    }

    // 旧手持机盘点
    private void setDetail(String orderNumber, List<String> list){
        //该位置下的资产
        TbAssetInventory _inventory = tbAssetInventoryMapper.selectTbAssetInventoryByNumber(orderNumber);
        TbAssetInformation information = new TbAssetInformation();
        String location = _inventory.getInventoryLocation();
        information.setLocationNumber(location);
        List<String> childrens = new RecursionUtil().getNumberWithChildren(locationMapper, location);
        information.setNlist(childrens);
        List<TbAssetInformation> informations = informationMapper.selectTbAssetInformationList(information);
        if (informations == null || informations.isEmpty() ){
            return ;
        }
        //该位置下资产rfid list
        List<String> _list = informations.stream().map(TbAssetInformation::getEpc).collect(Collectors.toList());

        //已盘点,1
        List<String> green = (List<String>) CollectionUtil.intersection(_list, list);
        //未盘点,2
        List<String> red = new ArrayList<>(_list);
        red.removeAll(list);
        //异常(多余),0
        List<String> yellow = new ArrayList<>(list);
        yellow.removeAll(_list);
        //插入详细盘点信息
        TbInventoryDetail detail = new TbInventoryDetail();
        //已盘
        setInventoryDetail(green, detail, orderNumber, 1);
        //未盘
        setInventoryDetail(red, detail, orderNumber, 2);
        //异常
        setInventoryDetail(yellow, detail, orderNumber, 0);
    }

    // 旧手持机盘点
    private void setInventoryDetail(List<String> list, TbInventoryDetail detail, String orderNumber, Integer isUpdate){
        for (String epc : list) {
            detail.setOrderNumber(orderNumber);
            TbAssetInformation tbAssetInformation = informationMapper.selectTbAssetInformationByEpc(epc);
            if (tbAssetInformation == null) {
                continue;
            }
            detail.setInventoryMetadata(JSONUtil.toJsonStr(tbAssetInformation));
            detail.setIsUpdateData(isUpdate);
            tbInventoryDetailMapper.insertTbInventoryDetail(detail);
        }
    }
}
