package com.zcloud.personnel.positioning.command.query;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zcloud.personnel.positioning.dto.clientobject.BiOverviewCO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
public class BiOverviewCache {
    private static final Logger LOGGER = LoggerFactory.getLogger(BiOverviewCache.class);
    private static final String KEY_PREFIX = "personnel-positioning:bi:overview:";
    private static final Duration TTL = Duration.ofSeconds(15);

    private final ObjectMapper objectMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final ConcurrentMap<String, CacheEntry> localCache = new ConcurrentHashMap<>();

    public BiOverviewCache(ObjectMapper objectMapper,
                           ObjectProvider<StringRedisTemplate> stringRedisTemplateProvider) {
        this.objectMapper = objectMapper;
        this.stringRedisTemplate = stringRedisTemplateProvider.getIfAvailable();
    }

    public BiOverviewCO get(String scopeKey) {
        String key = redisKey(scopeKey);
        CacheEntry local = localCache.get(key);
        long now = System.currentTimeMillis();
        if (local != null && local.expireAt > now) {
            return local.value;
        }
        if (stringRedisTemplate == null) {
            return null;
        }
        try {
            String json = stringRedisTemplate.opsForValue().get(key);
            if (json == null) {
                return null;
            }
            BiOverviewCO value = objectMapper.readValue(json, BiOverviewCO.class);
            localCache.put(key, new CacheEntry(value, now + TTL.toMillis()));
            return value;
        } catch (Exception e) {
            LOGGER.warn("Read BI overview cache failed, key={}", key, e);
            return null;
        }
    }

    public void put(String scopeKey, BiOverviewCO value) {
        String key = redisKey(scopeKey);
        localCache.put(key, new CacheEntry(value, System.currentTimeMillis() + TTL.toMillis()));
        if (stringRedisTemplate == null) {
            return;
        }
        try {
            stringRedisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(value), TTL);
        } catch (Exception e) {
            LOGGER.warn("Write BI overview cache failed, key={}", key, e);
        }
    }

    private String redisKey(String scopeKey) {
        return KEY_PREFIX + scopeKey;
    }

    private static class CacheEntry {
        private final BiOverviewCO value;
        private final long expireAt;

        private CacheEntry(BiOverviewCO value, long expireAt) {
            this.value = value;
            this.expireAt = expireAt;
        }
    }
}
