package service

import (
    "strings"
    "testing"
)

func TestFeatureRegistry_ResolveTemplate_SingleFeature(t *testing.T) {
    reg := NewFeatureRegistry()

    result, err := reg.ResolveTemplate([]string{"face"})
    if err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
    if result.Composed {
        t.Errorf("expected single template, got composed=true")
    }
    // Most specific template for face-only: std_face_recognition_stream (covers 1 feature)
    // std_workshop_face_recognition_shoe_alarm covers 2 features, less specific.
    if result.TemplateName != "std_face_recognition_stream" {
        t.Errorf("expected std_face_recognition_stream (most specific), got %s", result.TemplateName)
    }
}

func TestFeatureRegistry_ResolveTemplate_TwoFeaturesWithCommonTemplate(t *testing.T) {
    reg := NewFeatureRegistry()

    // face + shoe both have std_workshop_face_recognition_shoe_alarm in common
    result, err := reg.ResolveTemplate([]string{"face", "shoe"})
    if err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
    if result.Composed {
        t.Errorf("expected single template, got composed=true")
    }
    if result.TemplateName != "std_workshop_face_recognition_shoe_alarm" {
        t.Errorf("expected std_workshop_face_recognition_shoe_alarm, got %s", result.TemplateName)
    }
}

func TestFeatureRegistry_ResolveTemplate_ComposedNeeded(t *testing.T) {
    reg := NewFeatureRegistry()

    // Add a feature with a separate template so intersection is empty.
    // We temporarily add intrusion with its own template for testing.
    reg.features["intrusion"] = &FeatureDef{
        Key:       "intrusion",
        Label:     "区域入侵",
        Templates: []string{"std_intrusion_detection"},
    }

    // face → [std_workshop..., std_face_recog]
    // intrusion → [std_intrusion_detection]
    // Intersection = empty → Composed = true
    result, err := reg.ResolveTemplate([]string{"face", "intrusion"})
    if err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
    if !result.Composed {
        t.Errorf("expected composed=true, got false")
    }
    if !strings.HasPrefix(result.TemplateName, "auto_") {
        t.Errorf("composed template should start with auto_, got %s", result.TemplateName)
    }
    // composePrimary is the first template from the first feature (face)
    if result.composePrimary != "std_workshop_face_recognition_shoe_alarm" {
        t.Errorf("expected compose primary std_workshop_face_recognition_shoe_alarm, got %s", result.composePrimary)
    }
}

func TestFeatureRegistry_ResolveTemplate_UnavailableFeature(t *testing.T) {
    reg := NewFeatureRegistry()

    // helmet has no templates yet
    _, err := reg.ResolveTemplate([]string{"helmet"})
    if err == nil {
        t.Fatal("expected error for unavailable feature, got nil")
    }
    if !strings.Contains(err.Error(), "尚未就绪") {
        t.Errorf("error should mention 尚未就绪, got: %v", err)
    }
}

func TestFeatureRegistry_ResolveTemplate_UnknownFeature(t *testing.T) {
    reg := NewFeatureRegistry()

    _, err := reg.ResolveTemplate([]string{"face", "nonexistent"})
    if err == nil {
        t.Fatal("expected error for unknown feature, got nil")
    }
    if !strings.Contains(err.Error(), "未知") {
        t.Errorf("error should mention 未知, got: %v", err)
    }
}

func TestFeatureRegistry_ResolveTemplate_Empty(t *testing.T) {
    reg := NewFeatureRegistry()

    _, err := reg.ResolveTemplate(nil)
    if err == nil {
        t.Fatal("expected error for nil, got nil")
    }
}

func TestFeatureRegistry_ResolveTemplate_Dedup(t *testing.T) {
    reg := NewFeatureRegistry()

    // Duplicate keys should be deduplicated
    result, err := reg.ResolveTemplate([]string{"face", "face", "shoe"})
    if err != nil {
        t.Fatalf("unexpected error: %v", err)
    }
    if result.Composed {
        t.Errorf("expected single template, got composed=true")
    }
}

func TestIntersectTemplateLists(t *testing.T) {
    tests := []struct {
        name   string
        lists  [][]string
        expect []string
    }{
        {
            name:   "empty",
            lists:  nil,
            expect: nil,
        },
        {
            name:   "single list returns same list",
            lists:  [][]string{{"a", "b", "c"}},
            expect: []string{"a", "b", "c"},
        },
        {
            name:   "partial intersection",
            lists:  [][]string{{"a", "b", "c"}, {"b", "c", "d"}},
            expect: []string{"b", "c"},
        },
        {
            name:   "no intersection",
            lists:  [][]string{{"a", "b"}, {"c", "d"}},
            expect: nil,
        },
        {
            name:   "three lists",
            lists:  [][]string{{"a", "b", "c"}, {"b", "c"}, {"c", "b", "a"}},
            expect: []string{"b", "c"},
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := intersectTemplateLists(tt.lists)
            if len(got) != len(tt.expect) {
                t.Errorf("len = %d, want %d (got %v)", len(got), len(tt.expect), got)
                return
            }
            for i := range got {
                if got[i] != tt.expect[i] {
                    t.Errorf("at %d: got %q, want %q", i, got[i], tt.expect[i])
                }
            }
        })
    }
}

func TestFeatureRegistry_AllFeatures(t *testing.T) {
    reg := NewFeatureRegistry()
    all := reg.AllFeatures()
    if len(all) < 3 {
        t.Errorf("expected at least 3 features, got %d", len(all))
    }
    // Verify sorted by key
    for i := 1; i < len(all); i++ {
        if all[i].Key < all[i-1].Key {
            t.Errorf("features not sorted: %q before %q", all[i-1].Key, all[i].Key)
        }
    }
}
