package com.lingniu.ingest.protocol.gb32960.auth;

import com.lingniu.ingest.protocol.gb32960.config.Gb32960Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

/**
 * GB/T 32960 VIN 白名单校验器。
 *
 * <p>线程安全：内部持有 {@code AtomicReference<Set>}，支持运行时热替换白名单
 * （未来可扩展为从 Nacos / 数据库定时刷新）。
 *
 * <p>该校验只决定是否允许设备继续进入接收链路，不负责车辆主数据注册。生产环境若打开白名单，
 * 需要确保新增车辆先同步到这里，否则终端会收到 VIN_NOT_EXIST 应答并断开。
 */
public final class Gb32960VinAuthorizer {

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

    private final boolean enabled;
    private final boolean caseSensitive;
    private final AtomicReference<Set<String>> whitelist;

    public Gb32960VinAuthorizer(Gb32960Properties.Auth cfg) {
        this.enabled = cfg.isEnabled();
        this.caseSensitive = cfg.isCaseSensitive();
        this.whitelist = new AtomicReference<>(cfg.normalizedWhitelist());
        log.info("[gb32960] VIN authorizer enabled={} caseSensitive={} whitelistSize={}",
                enabled, caseSensitive, this.whitelist.get().size());
    }

    /**
     * 鉴权。
     *
     * @return true 通过；false 拒绝（调用方应发送 0x04 VIN_NOT_EXIST 应答并关闭连接）
     */
    public boolean isAllowed(String vin) {
        if (!enabled) return true;
        if (vin == null || vin.isBlank()) return false;
        // 默认大小写不敏感，以容忍部分平台把 VIN 小写转发；规范 VIN 本身仍应为大写。
        String key = caseSensitive ? vin.trim() : vin.trim().toUpperCase();
        return whitelist.get().contains(key);
    }

    public boolean isEnforcing() {
        return enabled;
    }

    public int whitelistSize() {
        return whitelist.get().size();
    }

    /** 运行时热更新。接入 Nacos/DB 监听后调用。 */
    public void replaceWhitelist(Set<String> newVins) {
        Set<String> norm = Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>(newVins.size()));
        for (String v : newVins) {
            if (v == null || v.isBlank()) continue;
            norm.add(caseSensitive ? v.trim() : v.trim().toUpperCase());
        }
        this.whitelist.set(norm);
        log.info("[gb32960] VIN whitelist replaced size={}", norm.size());
    }
}
