package com.bonus.core.device.door.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.core.customer.api.CustInfoApi;
import com.bonus.core.customer.model.CustInfo;
import com.bonus.core.device.door.enums.TriggerTypeEnum;
import com.bonus.core.device.door.mapper.DcAutoRuleDetailMapper;
import com.bonus.core.device.door.model.DcAutoRuleDetail;
import com.bonus.core.device.door.model.DcAutoRuleTrigger;
import com.bonus.core.device.door.model.DcCustDoor;
import com.bonus.core.device.door.service.DcAutoRuleDetailService;
import com.bonus.core.device.door.service.DcAutoRuleTriggerService;
import com.bonus.core.device.door.service.DcCustDoorService;
import com.bonus.core.device.door.service.DcGroupDoorService;
import com.bonus.core.device.manage.service.DeviceDcDoorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.bonus.core.device.door.model.DcGroupDoor;
import javax.annotation.Resource;
import java.lang.invoke.SerializedLambda;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
public class DcAutoRuleDetailServiceImpl extends ServiceImpl<DcAutoRuleDetailMapper, DcAutoRuleDetail> implements DcAutoRuleDetailService {
   @Autowired
   @Lazy
   private CustInfoApi custInfoApi;
   @Resource
   @Lazy
   private DcAutoRuleTriggerService dcAutoRuleTriggerService;
   @Resource
   @Lazy
   private DeviceDcDoorService deviceDcDoorService;
   @Resource
   @Lazy
   private DcGroupDoorService dcGroupDoorService;
   @Resource
   @Lazy
   private DcCustDoorService dcCustDoorService;

   public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
      Map<Object, Boolean> seen = new ConcurrentHashMap();
      return (t) -> {
         return seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
      };
   }

   @Override
   public Boolean checkUser(Long custId, TriggerTypeEnum triggerTypeEnum) {
      List<DcAutoRuleTrigger> triggerTypes = this.dcAutoRuleTriggerService.getByTriggerType(triggerTypeEnum.getKey());
      if (triggerTypes.isEmpty()) {
         return false;
      } else {
         List<Integer> ruleIds = (List)triggerTypes.stream().map(DcAutoRuleTrigger::getRuleId).distinct().collect(Collectors.toList());
         if (ruleIds.isEmpty()) {
            return false;
         } else {
            CustInfo custInfoByCustId = this.custInfoApi.getCustInfoByCustId(custId);
            Integer psnType = custInfoByCustId.getPsnType();
            Long orgId = custInfoByCustId.getOrgId();
            LambdaQueryWrapper<DcAutoRuleDetail> wrapper = Wrappers.lambdaQuery(DcAutoRuleDetail.class)
                    .select(DcAutoRuleDetail::getGroupId)
                    .in(DcAutoRuleDetail::getRuleId, ruleIds)
                    .eq(DcAutoRuleDetail::getOrgId, orgId);
            if (ObjectUtil.isEmpty(psnType)) {
               wrapper.isNull(DcAutoRuleDetail::getPsnType);
            } else {
               wrapper.eq(DcAutoRuleDetail::getPsnType, psnType);
            }

            List<Integer> groupIds = (List)this.list(wrapper).stream().map(DcAutoRuleDetail::getGroupId).distinct().collect(Collectors.toList());
            if (groupIds.isEmpty()) {
               return false;
            } else {
               switch (triggerTypeEnum) {
                  case EDIT:
                     this.dcCustDoorService.removeByCustId(custId);
                  case ADD:
                     List<DcCustDoor> dcCustDoors = null;
                     List doorIds;
                     if (groupIds.contains(1)) {
                        doorIds = this.deviceDcDoorService.getAllDeviceIds();
                        dcCustDoors = (List<DcCustDoor>) doorIds.stream().map(x -> new DcCustDoor()
                                .setCustId(custId)
                                .setDoorId((Long) x)
                                .setTimeZoneId(1)
                                .setRegistryResult(2)
                        ).collect(Collectors.toList());
                     } else if (groupIds.contains(2)) {
                        doorIds = this.deviceDcDoorService.getAllDeviceIds();
                        dcCustDoors = (List<DcCustDoor>)doorIds.stream().map((x) -> {
                           DcCustDoor dcCustDoor = new DcCustDoor();
                           dcCustDoor.setCustId(custId).setDoorId((Long)x).setTimeZoneId(2).setRegistryResult(2);
                           return dcCustDoor;
                        }).collect(Collectors.toList());
                     } else {
                        doorIds = this.dcGroupDoorService.getDistantDoorIdAndTimeZoneIdByGroupIds(groupIds);
                        dcCustDoors = (List<DcCustDoor>) doorIds.stream()
                                .filter(distinctByKey(DcGroupDoor::getDoorId))
                                .map(item -> BeanUtil.copyProperties(item, DcCustDoor.class)
                                        .setCustId(custId)
                                        .setRegistryResult(2))
                                .collect(Collectors.toList());
                     }

                     if (!dcCustDoors.isEmpty()) {
                        this.dcCustDoorService.saveBatch(dcCustDoors);
                     }
                     break;
                  case LOGOUT:
                     this.dcCustDoorService.removeByCustId(custId);
                     break;
                  default:
                     break;
               }

               return true;
            }
         }
      }
   }
}
