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

import com.lingniu.ingest.protocol.gb32960.auth.Gb32960PlatformAuthorizer;
import com.lingniu.ingest.protocol.gb32960.auth.Gb32960VinAuthorizer;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;

import java.net.InetSocketAddress;

/**
 * Access boundary for GB/T 32960 inbound channels.
 *
 * <p>Keeps authentication and channel-scoped platform identity out of the Netty
 * handler so the hot path can stay small and testable.
 *
 * <p>平台登入成功后，username 会绑定到 Netty channel attribute。后续实时上报帧没有账号字段，
 * 只能通过同一连接上的 attribute 找回平台账号，用于 Hyundai/广东扩展等 vendor profile 选择。
 */
public final class Gb32960AccessService {

    public static final AttributeKey<String> PLATFORM_ACCOUNT_ATTR =
            AttributeKey.valueOf("gb32960.platformAccount");

    private final Gb32960VinAuthorizer vinAuthorizer;
    private final Gb32960PlatformAuthorizer platformAuthorizer;

    public Gb32960AccessService(Gb32960VinAuthorizer vinAuthorizer,
                                Gb32960PlatformAuthorizer platformAuthorizer) {
        this.vinAuthorizer = vinAuthorizer;
        this.platformAuthorizer = platformAuthorizer;
    }

    public boolean isVinAllowed(String vin) {
        return vinAuthorizer.isAllowed(vin);
    }

    public boolean isVinWhitelistEnforcing() {
        return vinAuthorizer.isEnforcing();
    }

    public int vinWhitelistSize() {
        return vinAuthorizer.whitelistSize();
    }

    public boolean isPlatformAuthEnforcing() {
        return platformAuthorizer.isEnforcing();
    }

    public int platformPolicySize() {
        return platformAuthorizer.size();
    }

    public Gb32960PlatformAuthorizer.Result authenticatePlatformLogin(String username,
                                                                      String password,
                                                                      Channel channel) {
        // 鉴权策略可以按来源 IP 做限制，因此这里把远端地址从 Netty channel 中抽出。
        return platformAuthorizer.authenticate(username, password, peerIp(channel));
    }

    public void bindPlatformAccount(Channel channel, String username) {
        // 只绑定到当前连接，断线重连后必须重新平台登入，避免跨连接复用旧账号。
        channel.attr(PLATFORM_ACCOUNT_ATTR).set(username);
    }

    public String platformAccount(Channel channel) {
        return channel.hasAttr(PLATFORM_ACCOUNT_ATTR)
                ? channel.attr(PLATFORM_ACCOUNT_ATTR).get()
                : null;
    }

    private static String peerIp(Channel channel) {
        if (channel.remoteAddress() instanceof InetSocketAddress i) {
            return i.getAddress().getHostAddress();
        }
        return null;
    }
}
