package com.bonus.canteen.core.menu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.canteen.core.menu.api.MenuDishesApi;
import com.bonus.canteen.core.menu.dto.MenuNutritionAllDTO;
import com.bonus.canteen.core.menu.dto.MenuNutritionDTO;
import com.bonus.canteen.core.menu.entity.*;
import com.bonus.canteen.core.menu.mapper.*;
import com.bonus.canteen.core.menu.service.MenuMaterialService;
import com.bonus.canteen.core.menu.service.MenuNutritionService;
import com.bonus.canteen.core.menu.utils.NutritionEntity;
import com.bonus.canteen.core.menu.utils.NutritionEntityUtil;
import com.bonus.canteen.core.menu.vo.MenuNutritionAllVO;
import com.bonus.canteen.core.menu.vo.MenuNutritionPageVO;
import com.bonus.canteen.core.menu.vo.NutritionTypeVO;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.houqin.constant.DelFlagEnum;
import com.bonus.common.houqin.utils.LeBeanUtil;
import com.bonus.common.houqin.utils.id.Id;
import com.bonus.common.security.utils.SecurityUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class MenuNutritionServiceImpl extends ServiceImpl<MenuNutritionMapper, MenuNutrition> implements MenuNutritionService {
   private static final Logger log = LoggerFactory.getLogger(MenuNutritionServiceImpl.class);
   @Resource
   @Lazy
   private MenuDishesEffectRelationMapper menuDishesEffectRelationMapper;
   @Resource
   @Lazy
   private MenuMaterialDishesMapper menuMaterialDishesMapper;
   @Resource
   @Lazy
   private MenuDishesSuitMapper menuDishesSuitMapper;
   @Resource
   @Lazy
   private MenuSuitDishesMapper menuSuitDishesMapper;
   @Resource
   @Lazy
   private MenuNutritionService menuNutritionService;
   @Resource
   @Lazy
   private MenuMaterialService menuMaterialService;
   @Resource
   private MenuDishesApi menuDishesApi;

   @Override
   public List<NutritionTypeVO> getNutritionTypeList() {
      List<String> bigTypeList = ((MenuNutritionMapper)this.baseMapper).selectBigTypeList();
      List<NutritionTypeVO> nutritionTypeVOList = new ArrayList();
      Iterator var3 = bigTypeList.iterator();

      while(var3.hasNext()) {
         String bigType = (String)var3.next();
         NutritionTypeVO nutritionTypeVO = new NutritionTypeVO();
         List<String> littleTypeList = ((MenuNutritionMapper)this.baseMapper).selectLittleTypeList(bigType);
         nutritionTypeVO.setBigType(bigType);
         nutritionTypeVO.setLittleTypeList(littleTypeList);
         nutritionTypeVOList.add(nutritionTypeVO);
      }

      return nutritionTypeVOList;
   }

   @Override
   public List<MenuNutritionAllVO> getMenuNutritionAllList(MenuNutritionAllDTO content) {
      LambdaQueryWrapper<MenuNutrition> wrapper = Wrappers.lambdaQuery(MenuNutrition.class)
              .orderByDesc(MenuNutrition::getCrtime);
      String bigType = content.getBigType();
      String littleType = content.getLittleType();
      if (StringUtils.isNotBlank(bigType)) {
         wrapper.eq(MenuNutrition::getBigType, bigType);
      }

      if (StringUtils.isNotBlank(littleType)) {
         wrapper.eq(MenuNutrition::getLittleType, littleType);
      }

      return ((MenuNutritionMapper)this.baseMapper).selectAllList(wrapper);
   }

   @Override
   public NutritionEntity getMenuNutritionByMaterialId(Long dishesId) {
      List<MenuMaterialDishes> menuMaterialDishesList = this.menuMaterialDishesMapper.selectList((Wrapper)Wrappers.lambdaQuery(MenuMaterialDishes.class).eq(MenuMaterialDishes::getDishesId, dishesId));
      if (ObjectUtils.isEmpty(menuMaterialDishesList)) {
         throw new ServiceException("menu_no_material_dishes");
      } else {
         List<NutritionEntity> nutritionEntityList = new ArrayList();
         Iterator var4 = menuMaterialDishesList.iterator();

         while(var4.hasNext()) {
            MenuMaterialDishes menuMaterialDishes = (MenuMaterialDishes)var4.next();
            MenuMaterial menuMaterial = this.menuMaterialService.getByMaterialId(menuMaterialDishes.getMaterialId());
            if (ObjectUtils.isNotEmpty(menuMaterial)) {
               MenuNutrition menuNutrition = this.getByNutritionId(menuMaterial.getNutritionId());
               if (ObjectUtils.isNotEmpty(menuNutrition)) {
                  NutritionEntity nutritionEntity = new NutritionEntity();
                  LeBeanUtil.copyProperties(menuNutrition, nutritionEntity);
                  //TODO 临时添加的基础重量   待验证
                  nutritionEntity.setBaseWeight(menuNutrition.getWeight());
                  nutritionEntity.setWeight(menuMaterialDishes.getWeight());
                  nutritionEntityList.add(nutritionEntity);
               }
            }
         }

         if (ObjectUtils.isEmpty(nutritionEntityList)) {
            throw new ServiceException("menu_no_nu_detail");
         } else {
            return NutritionEntityUtil.countNutrition(nutritionEntityList);
         }
      }
   }

   @Override
   public MenuNutrition getByNutritionId(Long nutritionId) {
      return (this.baseMapper)
              .selectOne(new LambdaQueryWrapper<>(MenuNutrition.class)
                      .eq(MenuNutrition::getNutritionId, nutritionId));
   }

   @Override
   public void addMenuNutrition(MenuNutritionDTO menuNutritionDTO) {
      MenuNutrition menuNutrition = this.menuNutritionService.getOne(Wrappers.lambdaQuery(MenuNutrition.class)
              .eq(MenuNutrition::getNutritionCode, menuNutritionDTO.getNutritionCode())
              .or()
              .eq(MenuNutrition::getNutritionName, menuNutritionDTO.getNutritionName()).last("limit 1"));
      String username = SecurityUtils.getUsername();
      List effectIdList;
      if (ObjectUtils.isNotEmpty(menuNutrition)) {
         if (!DelFlagEnum.DEL_TRUE.key().equals(menuNutrition.getDelFlag())) {
            throw new ServiceException("menu_material_exist");
         }

         LeBeanUtil.copyProperties(menuNutritionDTO, menuNutrition);
         List<Long> suitIdList = menuNutritionDTO.getSuitablePopulationList();
         this.menuSuitDishesMapper.delete(Wrappers.lambdaQuery(MenuSuitDishes.class)
                 .eq(MenuSuitDishes::getDishesId, menuNutritionDTO.getNutritionId()));
         if (CollUtil.isNotEmpty(suitIdList)) {
            this.insertSuitDishesBatch(suitIdList, menuNutritionDTO.getNutritionId(), username);
         }

         effectIdList = menuNutritionDTO.getEffectList();
         this.menuDishesEffectRelationMapper.delete(Wrappers.lambdaQuery(MenuDishesEffectRelation.class)
                 .eq(MenuDishesEffectRelation::getDishesId, menuNutritionDTO.getNutritionId()));
         if (CollUtil.isNotEmpty(effectIdList)) {
            this.insertEffectBatch(effectIdList, menuNutritionDTO.getNutritionId(), username);
         }

         menuNutrition.setUptime(LocalDateTime.now());
         menuNutrition.setDelFlag(DelFlagEnum.DEL_FALSE.key());
         this.menuNutritionService.updateById(menuNutrition);
      } else {
         Long nutritionId = Id.next();
         effectIdList = menuNutritionDTO.getSuitablePopulationList();
         List<Long> effectIdLists = menuNutritionDTO.getEffectList();
         MenuNutrition menuNutrit = new MenuNutrition();
         LeBeanUtil.copyProperties(menuNutritionDTO, menuNutrit);
         menuNutrit.setNutritionId(Id.next());
         if (CollUtil.isNotEmpty(effectIdLists)) {
            this.insertSuitDishesBatch(effectIdLists, nutritionId, username);
         }

         if (CollUtil.isNotEmpty(effectIdList)) {
            this.insertEffectBatch(effectIdLists, nutritionId, username);
         }

         menuNutrit.setCrby(username);
         this.menuNutritionService.save(menuNutrit);
      }

   }

   @Override
   public void updateMenuNutrition(MenuNutritionDTO menuNutritionDTO) {
      MenuNutrition menuNutrition = this.menuNutritionService.getOne(Wrappers.lambdaQuery(MenuNutrition.class)
              .eq(MenuNutrition::getNutritionId, menuNutritionDTO.getNutritionId()));
      if (ObjectUtils.isEmpty(menuNutrition)) {
         throw new ServiceException("menu_material_not_exist2");
      } else {
         String username = SecurityUtils.getUsername();
         List<Long> suitIdList = menuNutritionDTO.getSuitablePopulationList();
         this.menuSuitDishesMapper.delete(Wrappers.lambdaQuery(MenuSuitDishes.class)
                 .eq(MenuSuitDishes::getDishesId, menuNutritionDTO.getNutritionId()));
         if (CollUtil.isNotEmpty(suitIdList)) {
            this.insertSuitDishesBatch(suitIdList, menuNutritionDTO.getNutritionId(), username);
         }

         List<Long> effectIdList = menuNutritionDTO.getEffectList();
         this.menuDishesEffectRelationMapper.delete(Wrappers.lambdaQuery(MenuDishesEffectRelation.class)
                 .eq(MenuDishesEffectRelation::getDishesId, menuNutritionDTO.getNutritionId()));
         if (CollUtil.isNotEmpty(effectIdList)) {
            this.insertEffectBatch(effectIdList, menuNutritionDTO.getNutritionId(), username);
         }

         LeBeanUtil.copyProperties(menuNutritionDTO, menuNutrition);
         menuNutrition.setUptime(LocalDateTime.now());
         this.menuNutritionService.updateById(menuNutrition);
         this.menuDishesApi.asyncUpdateDishesNutritionByNutritionId(menuNutritionDTO.getNutritionId());
      }
   }

   @Override
   public Page<MenuNutritionPageVO> getMenuNutritionPage(MenuNutritionDTO dto) {
      Page<MenuNutritionPageVO> page = new Page<>(dto.getCurrent(),dto.getSize());
      dto.setDelFlag(DelFlagEnum.DEL_FALSE.key());
      Page<MenuNutritionPageVO> resultPage = this.baseMapper.selectNutritionList(page, dto);
      List<MenuNutritionPageVO> menuNutritionPageVOList = resultPage.getRecords();
      log.info("营养素详情: {}", menuNutritionPageVOList);
      Iterator var7 = menuNutritionPageVOList.iterator();

      while(var7.hasNext()) {
         MenuNutritionPageVO nutritionPageVO = (MenuNutritionPageVO)var7.next();
         Long nutritionId = nutritionPageVO.getNutritionId();
         Integer delFlag = DelFlagEnum.DEL_FALSE.key();
         MenuSuitDishes suitDishes = new MenuSuitDishes();
         suitDishes.setDishesId(nutritionId);
         suitDishes.setDelFlag(delFlag);
         nutritionPageVO.setSuitablePopulationList(this.menuDishesSuitMapper.selectListByDishesId(suitDishes));
         MenuDishesEffectRelation menuDishesEffectRelation = new MenuDishesEffectRelation();
         menuDishesEffectRelation.setDishesId(nutritionId);
         menuDishesEffectRelation.setDelFlag(delFlag);
         nutritionPageVO.setEffectList(this.menuDishesEffectRelationMapper.selectListByDishesId(menuDishesEffectRelation));
      }

      return resultPage;
   }

   @Override
   public void removeByNutritionCode(Long nutritionId) {
      MenuNutrition menuNutrition =
              this.menuNutritionService.getOne(Wrappers.lambdaQuery(MenuNutrition.class)
                      .eq(MenuNutrition::getNutritionId, nutritionId));
      if (ObjectUtils.isEmpty(menuNutrition)) {
         throw new ServiceException("menu_material_not_exist");
      } else {
         List<MenuMaterial> menuMaterialList = this.menuMaterialService.list(Wrappers.lambdaQuery(MenuMaterial.class)
                 .eq(MenuMaterial::getNutritionId, nutritionId)
                 .eq(MenuMaterial::getDelFlag, DelFlagEnum.DEL_FALSE.key()));
         if (menuMaterialList != null && !menuMaterialList.isEmpty()) {
            throw new ServiceException("menu_material_use_dishes_del");
         } else {
            this.baseMapper.update(null,
                    (new LambdaUpdateWrapper<>(MenuNutrition.class).eq(MenuNutrition::getNutritionId, nutritionId))
                            .set(MenuNutrition::getDelFlag,
                            DelFlagEnum.DEL_TRUE.key()));
            this.menuSuitDishesMapper.update(null, Wrappers.lambdaUpdate(MenuSuitDishes.class)
                    .eq(MenuSuitDishes::getDishesId, nutritionId)
                    .set(MenuSuitDishes::getDelFlag, DelFlagEnum.DEL_TRUE.key()));
            this.menuDishesEffectRelationMapper.update(null, Wrappers.lambdaUpdate(MenuDishesEffectRelation.class)
                    .eq(MenuDishesEffectRelation::getDishesId, nutritionId)
                    .set(MenuDishesEffectRelation::getDelFlag, DelFlagEnum.DEL_TRUE.key()));
         }
      }
   }

   @Override
   public List<NutritionEntity> selectNutritionWeightList(Long dishesId) {
      List<MenuMaterialDishes> menuMaterialDishes = this.menuMaterialDishesMapper.selectList(Wrappers.lambdaQuery(MenuMaterialDishes.class)
              .select(MenuMaterialDishes::getMaterialId, MenuMaterialDishes::getWeight).eq(MenuMaterialDishes::getDishesId, dishesId));
      if (ObjectUtils.isEmpty(menuMaterialDishes)) {
         return new ArrayList<>();
      } else {
         List<Long> materialIds = menuMaterialDishes.stream().map(MenuMaterialDishes::getMaterialId).collect(Collectors.toList());
         Map<Long, Double> materialWeight =
                 menuMaterialDishes.stream().collect(Collectors.toMap(MenuMaterialDishes::getMaterialId, MenuMaterialDishes::getWeight));
         Map<Long, MenuMaterialNutrition> data = this.menuMaterialService.getMenuMaterialNutrition(materialIds);
         List<NutritionEntity> result = new ArrayList<>();
         Iterator var7 = menuMaterialDishes.iterator();

         while(var7.hasNext()) {
            MenuMaterialDishes menuMaterialDish = (MenuMaterialDishes)var7.next();
            MenuMaterialNutrition menuMaterialNutrition = data.get(menuMaterialDish.getMaterialId());
            if (ObjectUtils.isNotEmpty(menuMaterialNutrition)) {
               NutritionEntity nutritionEntity = BeanUtil.copyProperties(menuMaterialNutrition, NutritionEntity.class, new String[0]);
               nutritionEntity.setWeight(materialWeight.get(menuMaterialDish.getMaterialId()));
               nutritionEntity.setBaseWeight(100.0);
               result.add(nutritionEntity);
            }
         }

         return result;
      }
   }

   @Override
   public MenuNutrition getByNutritionName(String materialName) {
      return this.getOne(Wrappers.lambdaQuery(MenuNutrition.class).eq(MenuNutrition::getNutritionName, materialName)
              .last("limit 1"));
   }

   private void insertSuitDishesBatch(List<Long> suitIdList, Long nutritionId, String username) {
      List<MenuSuitDishes> suitDishesList = new ArrayList<>();
      Iterator var5 = suitIdList.iterator();

      while(var5.hasNext()) {
         Long suitId = (Long)var5.next();
         MenuSuitDishes suitDishes = new MenuSuitDishes();
         suitDishes.setDishesId(nutritionId);
         suitDishes.setSuitId(suitId);
         suitDishes.setCrby(username);
         suitDishesList.add(suitDishes);
      }

      this.menuSuitDishesMapper.insertBatch(suitDishesList);
   }

   private void insertEffectBatch(List<Long> effectIdList, Long nutritionId, String username) {
      List<MenuDishesEffectRelation> effectIdsList = new ArrayList<>();
      Iterator var5 = effectIdList.iterator();

      while(var5.hasNext()) {
         Long effectId = (Long)var5.next();
         MenuDishesEffectRelation menuDishesEffectRelation = new MenuDishesEffectRelation();
         menuDishesEffectRelation.setDishesId(nutritionId);
         menuDishesEffectRelation.setEffectId(effectId);
         menuDishesEffectRelation.setCrby(username);
         effectIdsList.add(menuDishesEffectRelation);
      }

      this.menuDishesEffectRelationMapper.insertBatch(effectIdsList);
   }

}
