package com.usky.vpp.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.usky.vpp.config.VppUnProperties;
import com.usky.vpp.util.VppUnMessageBuilder;
import com.usky.vpp.util.VppUnPayloadHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

/**
 * UN Token 缓存（TokenRequest 获取，默认约 30 分钟过期）
 */
@Component
public class VppUnTokenHolder {

    private static final Logger log = LoggerFactory.getLogger(VppUnTokenHolder.class);

    private final ReentrantLock lock = new ReentrantLock();

    @Autowired
    private VppUnProperties properties;

    @Autowired
    private VppUnHttpExecutor httpExecutor;

    @Autowired
    private ObjectMapper objectMapper;

    private volatile String token;
    private volatile Instant expiresAt = Instant.EPOCH;

    public String getToken() {
        if (!needsRefresh()) {
            return token;
        }
        lock.lock();
        try {
            if (!needsRefresh()) {
                return token;
            }
            refreshTokenInternal();
            return token;
        } finally {
            lock.unlock();
        }
    }

    public void invalidate() {
        lock.lock();
        try {
            token = null;
            expiresAt = Instant.EPOCH;
        } finally {
            lock.unlock();
        }
    }

    public void applyTokenResponse(Map<String, Object> response) {
        String newToken = VppUnPayloadHelper.getString(response, "token");
        if (!StringUtils.hasText(newToken)) {
            throw new IllegalStateException("TokenResponse 缺少 token");
        }
        lock.lock();
        try {
            token = newToken;
            int ttlMinutes = properties.getTokenTtlMinutes() != null ? properties.getTokenTtlMinutes() : 25;
            expiresAt = Instant.now().plusSeconds(ttlMinutes * 60L);
        } finally {
            lock.unlock();
        }
    }

    private boolean needsRefresh() {
        return !StringUtils.hasText(token) || Instant.now().isAfter(expiresAt);
    }

    private void refreshTokenInternal() {
        Map<String, Object> request = VppUnMessageBuilder.buildTokenRequest(properties);
        String responseBody = httpExecutor.postRaw("TokenRequest", request, false);
        try {
            Map<String, Object> response = objectMapper.readValue(responseBody, new TypeReference<Map<String, Object>>() {
            });
            Integer code = VppUnPayloadHelper.getInteger(response, "code");
            if (code != null && code != 200) {
                throw new IllegalStateException("TokenRequest 失败: " + response.get("description"));
            }
            String newToken = VppUnPayloadHelper.getString(response, "token");
            if (!StringUtils.hasText(newToken)) {
                throw new IllegalStateException("TokenResponse 缺少 token");
            }
            applyTokenResponse(response);
            log.info("UN Token 已刷新");
        } catch (IllegalStateException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new IllegalStateException("TokenResponse 解析失败", ex);
        }
    }
}
