package iace

import (
	"testing"
)

// TestIntegration_FullMatchFlow tests the complete pattern matching flow:
// components → tags → patterns → hazards/measures/evidence
func TestIntegration_FullMatchFlow(t *testing.T) {
	engine := NewPatternEngine()

	// Simulate a robot arm with electrical components and kinetic energy
	input := MatchInput{
		ComponentLibraryIDs: []string{"C001", "C061", "C071"}, // Roboterarm, Schaltschrank, SPS
		EnergySourceIDs:     []string{"EN01", "EN04"},         // Kinetic, Electrical
		LifecyclePhases:     []string{},
		CustomTags:          []string{},
	}

	output := engine.Match(input)

	// Should have matched patterns
	if len(output.MatchedPatterns) == 0 {
		t.Fatal("expected matched patterns for robot arm + electrical + SPS setup, got none")
	}

	// Should have suggested hazards
	if len(output.SuggestedHazards) == 0 {
		t.Fatal("expected suggested hazards, got none")
	}

	// Should have suggested measures
	if len(output.SuggestedMeasures) == 0 {
		t.Fatal("expected suggested measures, got none")
	}

	// Should have suggested evidence
	if len(output.SuggestedEvidence) == 0 {
		t.Fatal("expected suggested evidence, got none")
	}

	// Should have resolved tags
	if len(output.ResolvedTags) == 0 {
		t.Fatal("expected resolved tags, got none")
	}

	// Verify mechanical hazards are present (robot arm has moving_part, rotating_part)
	hasMechanical := false
	for _, h := range output.SuggestedHazards {
		if h.Category == "mechanical" || h.Category == "mechanical_hazard" {
			hasMechanical = true
			break
		}
	}
	if !hasMechanical {
		cats := make(map[string]bool)
		for _, h := range output.SuggestedHazards {
			cats[h.Category] = true
		}
		t.Errorf("expected mechanical hazards for robot arm, got categories: %v", cats)
	}

	// Verify electrical hazards are present (Schaltschrank has high_voltage)
	hasElectrical := false
	for _, h := range output.SuggestedHazards {
		if h.Category == "electrical" || h.Category == "electrical_hazard" {
			hasElectrical = true
			break
		}
	}
	if !hasElectrical {
		cats := make(map[string]bool)
		for _, h := range output.SuggestedHazards {
			cats[h.Category] = true
		}
		t.Errorf("expected electrical hazards for Schaltschrank, got categories: %v", cats)
	}
}

// TestIntegration_TagResolverToPatternEngine verifies the tag resolver output
// feeds correctly into the pattern engine.
func TestIntegration_TagResolverToPatternEngine(t *testing.T) {
	resolver := NewTagResolver()
	engine := NewPatternEngine()

	// Resolve tags for a hydraulic setup
	componentTags := resolver.ResolveComponentTags([]string{"C041"}) // Hydraulikpumpe
	energyTags := resolver.ResolveEnergyTags([]string{"EN05"})      // Hydraulische Energie

	allTags := resolver.ResolveTags([]string{"C041"}, []string{"EN05"}, nil)

	// All tags should be non-empty
	if len(componentTags) == 0 {
		t.Error("expected component tags for C041")
	}
	if len(energyTags) == 0 {
		t.Error("expected energy tags for EN05")
	}

	// Merged tags should include both
	tagSet := toSet(allTags)
	if !tagSet["hydraulic_part"] {
		t.Error("expected 'hydraulic_part' in merged tags")
	}
	if !tagSet["hydraulic_pressure"] {
		t.Error("expected 'hydraulic_pressure' in merged tags")
	}

	// Feed into pattern engine
	output := engine.Match(MatchInput{
		ComponentLibraryIDs: []string{"C041"},
		EnergySourceIDs:     []string{"EN05"},
	})

	if len(output.MatchedPatterns) == 0 {
		t.Error("expected patterns to match for hydraulic setup")
	}
}

// TestIntegration_AllComponentCategoriesProduceMatches verifies that every
// component category, when paired with its typical energy source, produces
// at least one pattern match.
func TestIntegration_AllComponentCategoriesProduceMatches(t *testing.T) {
	engine := NewPatternEngine()

	tests := []struct {
		name         string
		componentIDs []string
		energyIDs    []string
	}{
		{"mechanical", []string{"C001"}, []string{"EN01"}},         // Roboterarm + Kinetic
		{"drive", []string{"C031"}, []string{"EN02"}},              // Elektromotor + Rotational
		{"hydraulic", []string{"C041"}, []string{"EN05"}},          // Hydraulikpumpe + Hydraulic
		{"pneumatic", []string{"C051"}, []string{"EN06"}},          // Pneumatikzylinder + Pneumatic
		{"electrical", []string{"C061"}, []string{"EN04"}},         // Schaltschrank + Electrical
		{"control", []string{"C071"}, []string{"EN04"}},            // SPS + Electrical
		{"safety", []string{"C101"}, []string{"EN04"}},             // Not-Halt + Electrical
		{"it_network", []string{"C111"}, []string{"EN04", "EN19"}}, // Switch + Electrical + Data
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			output := engine.Match(MatchInput{
				ComponentLibraryIDs: tt.componentIDs,
				EnergySourceIDs:     tt.energyIDs,
			})
			if len(output.MatchedPatterns) == 0 {
				t.Errorf("category %s: expected at least one pattern match, got none (resolved tags: %v)",
					tt.name, output.ResolvedTags)
			}
		})
	}
}

// TestIntegration_PatternsSuggestHazardCategories verifies that pattern-suggested
// hazard categories cover the main safety domains.
func TestIntegration_PatternsSuggestHazardCategories(t *testing.T) {
	engine := NewPatternEngine()

	// Full industrial setup: robot arm + electrical panel + PLC + network
	output := engine.Match(MatchInput{
		ComponentLibraryIDs: []string{"C001", "C061", "C071", "C111"},
		EnergySourceIDs:     []string{"EN01", "EN04"},
	})

	categories := make(map[string]bool)
	for _, h := range output.SuggestedHazards {
		categories[h.Category] = true
	}

	// Should cover mechanical and electrical hazards (naming may use _hazard suffix)
	hasMech := categories["mechanical"] || categories["mechanical_hazard"]
	hasElec := categories["electrical"] || categories["electrical_hazard"]
	if !hasMech {
		t.Errorf("expected mechanical hazard category in suggestions, got: %v", categories)
	}
	if !hasElec {
		t.Errorf("expected electrical hazard category in suggestions, got: %v", categories)
	}
}

// TestIntegration_EvidenceSuggestionsPerReductionType tests that evidence
// can be found for each reduction type.
func TestIntegration_EvidenceSuggestionsPerReductionType(t *testing.T) {
	resolver := NewTagResolver()

	tests := []struct {
		reductionType string
		evidenceTags  []string
	}{
		{"design", []string{"design_evidence", "analysis_evidence"}},
		{"protective", []string{"test_evidence", "inspection_evidence"}},
		{"information", []string{"training_evidence", "operational_evidence"}},
	}

	for _, tt := range tests {
		t.Run(tt.reductionType, func(t *testing.T) {
			evidence := resolver.FindEvidenceByTags(tt.evidenceTags)
			if len(evidence) == 0 {
				t.Errorf("no evidence found for %s reduction type (tags: %v)", tt.reductionType, tt.evidenceTags)
			}
		})
	}
}

// TestIntegration_LibraryConsistency verifies components and energy sources have tags.
func TestIntegration_LibraryConsistency(t *testing.T) {
	components := GetComponentLibrary()
	energySources := GetEnergySources()
	taxonomy := GetTagTaxonomy()

	// Taxonomy should be populated
	if len(taxonomy) == 0 {
		t.Fatal("tag taxonomy is empty")
	}

	// All components should have at least one tag
	for _, comp := range components {
		if len(comp.Tags) == 0 {
			t.Errorf("component %s has no tags", comp.ID)
		}
	}

	// All energy sources should have at least one tag
	for _, es := range energySources {
		if len(es.Tags) == 0 {
			t.Errorf("energy source %s has no tags", es.ID)
		}
	}

	// Component tags should mostly exist in taxonomy (allow some flexibility)
	taxonomyIDs := toSet(func() []string {
		ids := make([]string, len(taxonomy))
		for i, tag := range taxonomy {
			ids[i] = tag.ID
		}
		return ids
	}())

	missingCount := 0
	totalTags := 0
	for _, comp := range components {
		for _, tag := range comp.Tags {
			totalTags++
			if !taxonomyIDs[tag] {
				missingCount++
			}
		}
	}
	// At least 90% of component tags should be in taxonomy
	if totalTags > 0 {
		coverage := float64(totalTags-missingCount) / float64(totalTags) * 100
		if coverage < 90 {
			t.Errorf("only %.0f%% of component tags exist in taxonomy (%d/%d)", coverage, totalTags-missingCount, totalTags)
		}
	}
}
