package com.lingniu.ingest.protocol.gb32960.codec.profile;

import com.lingniu.ingest.protocol.gb32960.codec.Gb32960ParserContext;
import com.lingniu.ingest.protocol.gb32960.config.Gb32960Properties;
import com.lingniu.ingest.protocol.gb32960.model.ProtocolVersion;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class RuleBasedVendorExtensionSelectorTest {

    @Test
    void platformAccountMatchHits() {
        var ext = entry("guangdong-fc", List.of("lingniu"), List.of(), List.of());
        var selector = new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc"));
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "LNV1234567890ABCD", "lingniu");
        assertThat(selector.select(ctx)).isEqualTo("guangdong-fc");
    }

    @Test
    void vinExactMatchHits() {
        var ext = entry("guangdong-fc", List.of(), List.of("LNV1234567890ABCD"), List.of());
        var selector = new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc"));
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "lnv1234567890abcd", null);
        assertThat(selector.select(ctx))
                .as("VIN match should be case-insensitive")
                .isEqualTo("guangdong-fc");
    }

    @Test
    void vinPrefixMatchHits() {
        var ext = entry("guangdong-fc", List.of(), List.of(), List.of("LNVFC", "LZG"));
        var selector = new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc"));
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "LNVFC0001", null);
        assertThat(selector.select(ctx)).isEqualTo("guangdong-fc");
    }

    @Test
    void noMatchReturnsNull() {
        var ext = entry("guangdong-fc", List.of("other"), List.of(), List.of());
        var selector = new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc"));
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "ZZZ", "lingniu");
        assertThat(selector.select(ctx)).isNull();
    }

    @Test
    void firstMatchWinsTopDown() {
        var first = entry("guangdong-fc", List.of("lingniu"), List.of(), List.of());
        var second = entry("guangdong-fc", List.of(), List.of(), List.of("LNV"));
        var selector = new RuleBasedVendorExtensionSelector(
                List.of(first, second), Set.of("guangdong-fc"));
        // 即便两条都能命中，应返回第一条匹配 entry 的 name（这里凑巧一样）
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "LNV1", "lingniu");
        assertThat(selector.select(ctx)).isEqualTo("guangdong-fc");
    }

    @Test
    void emptyConfigReturnsNullWithoutScanning() {
        var selector = new RuleBasedVendorExtensionSelector(List.of(), Set.of("guangdong-fc"));
        var ctx = new Gb32960ParserContext(ProtocolVersion.V2016, "ANY", "ANY");
        assertThat(selector.select(ctx)).isNull();
    }

    @Test
    void unknownExtensionNameRejectedAtConstruction() {
        var ext = entry("not-in-catalog", List.of("x"), List.of(), List.of());
        assertThatThrownBy(() ->
                new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc")))
                .isInstanceOf(IllegalStateException.class)
                .hasMessageContaining("not-in-catalog");
    }

    @Test
    void resultIsCachedPerAccountVinTuple() {
        var ext = entry("guangdong-fc", List.of("lingniu"), List.of(), List.of());
        var selector = new RuleBasedVendorExtensionSelector(List.of(ext), Set.of("guangdong-fc"));
        var ctx1 = new Gb32960ParserContext(ProtocolVersion.V2016, "VIN1", "lingniu");
        var ctx2 = new Gb32960ParserContext(ProtocolVersion.V2016, "VIN1", "lingniu");
        selector.select(ctx1);
        selector.select(ctx2);
        // 同一个 (account, vin) 应只产生一个 cache 条目
        assertThat(selector.cacheSize()).isEqualTo(1);

        var ctx3 = new Gb32960ParserContext(ProtocolVersion.V2016, "VIN2", "lingniu");
        selector.select(ctx3);
        assertThat(selector.cacheSize()).isEqualTo(2);
    }

    private static Gb32960Properties.VendorExtension entry(String name,
                                                           List<String> accounts,
                                                           List<String> vins,
                                                           List<String> vinPrefixes) {
        var e = new Gb32960Properties.VendorExtension();
        e.setName(name);
        var m = new Gb32960Properties.VendorExtension.Match();
        m.setPlatformAccounts(accounts);
        m.setVins(vins);
        m.setVinPrefixes(vinPrefixes);
        e.setMatch(m);
        return e;
    }
}
