package com.bonus.canteen.core.allocation.alloc.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bonus.common.houqin.constant.LeConstants;
import com.bonus.canteen.core.allocation.alloc.mapper.AllocPayMetadataMapper;
import com.bonus.canteen.core.allocation.alloc.model.AllocMetadata;
import com.bonus.canteen.core.allocation.alloc.service.AllocMetadataService;
import com.bonus.canteen.core.allocation.api.AllocStallApi;
import com.bonus.canteen.core.allocation.canteen.model.AllocStall;
import com.bonus.canteen.core.allocation.util.MetadataUtil;
import com.bonus.canteen.core.common.enums.MetadataModelTypeEnum;
import com.bonus.canteen.core.common.redis.RedisUtil;
import com.bonus.canteen.core.common.utils.TenantContextHolder;
import com.bonus.common.houqin.utils.id.Id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AllocMetadataServiceImpl extends ServiceImpl<AllocPayMetadataMapper, AllocMetadata> implements AllocMetadataService {
    private static final Logger log = LoggerFactory.getLogger(AllocMetadataServiceImpl.class);
    private static final String CACHE_PREFIX = "yst:";
    private static final String CACHE_KEY = "pay-mata-data";
    private static final long CACHE_SECONDS = 3600L;
    @Resource
    private AllocStallApi allocStallApi;

    @Override
    public List<AllocMetadata> listPayMetadataCacheable(MetadataModelTypeEnum modelTypeEnum) {
        return this.listPayMetadataCacheable(modelTypeEnum.getKey());
    }
    private List<AllocMetadata> listPayMetadataCacheable(String modelType) {
        String var10000 = this.getCacheKeyPrefix();
        String cacheKey = var10000 + modelType;
        Object cacheObj = RedisUtil.getObj(cacheKey);
        if (cacheObj instanceof List) {
            return (List) cacheObj;
        } else {
            List<AllocMetadata> selectList = this.baseMapper.selectList(Wrappers.lambdaQuery(AllocMetadata.class).eq(AllocMetadata::getModelType, modelType));
            RedisUtil.setObj(cacheKey, selectList, 3600L);
            return selectList;
        }
    }
    @Override
    public String getCacheKeyPrefix() {
        return "yst:" + TenantContextHolder.getTenantId() + ":pay-mata-data:";
    }

    @Override
    public List<AllocMetadata> listPayMetadataByType(MetadataModelTypeEnum modelType, Long canteenId, Long stallId) {
        if (ObjectUtil.isNotNull(stallId) && ObjectUtil.isNull(canteenId)) {
            AllocStall stall = this.allocStallApi.getAllocStall(stallId);
            if (!ObjectUtil.isNull(stall) && !ObjectUtil.isNull(stall.getCanteenId())) {
                canteenId = stall.getCanteenId();
            } else {
                log.warn("【配置项】未查到档口关联食堂：{},{},{}", new Object[]{modelType, canteenId, stallId});
            }
        }

        Long finalCanteenId = canteenId;
        return (List) this.listPayMetadataCacheable(modelType).stream().filter((s) -> {
            return ObjectUtil.equal(s.getCanteenId(), finalCanteenId) && ObjectUtil.equal(s.getStallId(), stallId);
        }).collect(Collectors.toList());
    }


    public String getPayMetadataValue(MetadataModelTypeEnum modelTypeEnum, String modelKey, Long canteenId, Long stallId) {
        return (String) this.listPayMetadataByType(modelTypeEnum, canteenId, stallId).stream().filter((s) -> {
            return StrUtil.equals(s.getModelKey(), modelKey);
        }).map(AllocMetadata::getModelValue).filter(Objects::nonNull).findFirst().orElse("");
    }

    @Override
    public void savePayMetadata(List<AllocMetadata> payMetadataList) {
        Map<String, AllocMetadata> metadataMap = (Map) ((AllocPayMetadataMapper) this.baseMapper).selectList(Wrappers.lambdaQuery(AllocMetadata.class)).stream().collect(Collectors.toMap(AllocMetadata::uniqueKey, Function.identity()));
        Iterator var3 = payMetadataList.iterator();

        AllocMetadata newMetadata;
        while (var3.hasNext()) {
            newMetadata = (AllocMetadata) var3.next();
            if (newMetadata.getCanteenId() == null && newMetadata.getStallId() == null) {
                newMetadata.setIfActive(LeConstants.COMMON_YES);
            }

            MetadataUtil.metadataPathFieldHandler(newMetadata.getModelKey(), newMetadata.getModelValue(), false);
            AllocMetadata oldMetadata = (AllocMetadata) metadataMap.get(newMetadata.uniqueKey());
            if (ObjectUtil.isNull(oldMetadata)) {
                newMetadata.setMetadataId(Id.next());
                this.save(newMetadata);
            } else if (!StrUtil.equals(oldMetadata.getModelValue(), newMetadata.getModelValue())) {
                this.update(Wrappers.<AllocMetadata>lambdaUpdate().eq(AllocMetadata::getMetadataId,
                                oldMetadata.getMetadataId()).set(AllocMetadata::getModelValue, newMetadata.getModelValue())
                        .set(AllocMetadata::getModelKeyRemark, newMetadata.getModelKeyRemark()));
            }
        }

        var3 = payMetadataList.iterator();

        while (true) {
            do {
                if (!var3.hasNext()) {
                    this.clearCache();
                    return;
                }

                newMetadata = (AllocMetadata) var3.next();
            } while (newMetadata.getCanteenId() == null && newMetadata.getStallId() == null);

            if (MetadataModelTypeEnum.supportSeparatedTypes().contains(newMetadata.getModelType()) && MetadataModelTypeEnum.modelKeyOfSeparatedType(newMetadata.getModelType()).equals(newMetadata.getModelKey())) {
                this.updateIfActive(newMetadata.getModelType(), "1".equals(newMetadata.getModelValue()), newMetadata.getCanteenId(), newMetadata.getStallId());
            }
        }
    }

    private void clearCache() {
        RedisUtil.deleteByPattern(this.getCacheKeyPrefix() + "*");
    }

    public void updateIfActive(String modelType, boolean ifActive, Long canteenId, Long stallId) {
        ((AllocPayMetadataMapper) this.baseMapper).update((AllocMetadata) null,
                (Wrappers.<AllocMetadata>lambdaUpdate().eq(AllocMetadata::getModelType, modelType))
                        .eq(canteenId != null, AllocMetadata::getCanteenId, canteenId)
                        .isNull(canteenId == null, AllocMetadata::getCanteenId)
                        .eq(stallId != null, AllocMetadata::getStallId, stallId)
                        .isNull(stallId == null, AllocMetadata::getStallId)
                        .set(AllocMetadata::getIfActive, ifActive ? LeConstants.COMMON_YES : LeConstants.COMMON_NO));
        this.clearCache();
    }

    public List<AllocMetadata> listPayMetadataByTypeAreaId(MetadataModelTypeEnum modelType, Long areaId) {
        return this.listPayMetadataCacheable(modelType).stream().filter((s) -> {
            return ObjectUtil.equal(s.getAreaId(), areaId);
        }).collect(Collectors.toList());
    }

}
