package checker

import (
	"strings"
	"testing"
)

func TestFormatViolations_NoViolations(t *testing.T) {
	result := &CheckResult{
		Violations:   []Violation{},
		TotalChecked: 10,
	}

	output := FormatViolations(result)
	expected := "✓ No policy violations found"

	if output != expected {
		t.Errorf("Expected %q, got %q", expected, output)
	}
}

func TestFormatViolations_WithViolations(t *testing.T) {
	result := &CheckResult{
		Violations: []Violation{
			{
				File:       "main.go",
				LineNumber: 10,
				PolicyName: "No hardcoded secrets",
				Message:    "Potential hardcoded API key detected",
				Code:       "apiKey := \"sk-1234567890\"",
			},
			{
				File:       "config.go",
				LineNumber: 5,
				PolicyName: "Use environment variables",
				Message:    "Configuration should use environment variables",
				Code:       "var token = \"abc123\"",
			},
		},
		TotalChecked: 50,
	}

	output := FormatViolations(result)

	// Check that output contains expected elements
	if !strings.Contains(output, "✗ Found 2 policy violation(s)") {
		t.Errorf("Expected violation count in output, got: %s", output)
	}
	if !strings.Contains(output, "main.go") {
		t.Errorf("Expected file name 'main.go' in output")
	}
	if !strings.Contains(output, "config.go") {
		t.Errorf("Expected file name 'config.go' in output")
	}
	if !strings.Contains(output, "10:") {
		t.Errorf("Expected line number 10 in output")
	}
	if !strings.Contains(output, "Potential hardcoded API key detected") {
		t.Errorf("Expected violation message in output")
	}
}

func TestFormatClaudeInstructions_NoViolations(t *testing.T) {
	result := &CheckResult{
		Violations:   []Violation{},
		TotalChecked: 10,
	}

	output := FormatClaudeInstructions(result)

	if output != "" {
		t.Errorf("Expected empty string for no violations, got: %s", output)
	}
}

func TestFormatClaudeInstructions_WithViolations(t *testing.T) {
	result := &CheckResult{
		Violations: []Violation{
			{
				File:       "main.go",
				LineNumber: 10,
				PolicyName: "No hardcoded secrets",
				Message:    "Potential hardcoded API key detected",
				Code:       "apiKey := \"sk-1234567890\"",
			},
			{
				File:       "main.go",
				LineNumber: 15,
				PolicyName: "No hardcoded secrets",
				Message:    "Potential hardcoded password detected",
				Code:       "password := \"secret123\"",
			},
			{
				File:       "config.go",
				LineNumber: 5,
				PolicyName: "Use environment variables",
				Message:    "Configuration should use environment variables",
				Code:       "var token = \"abc123\"",
			},
		},
		TotalChecked: 50,
	}

	output := FormatClaudeInstructions(result)

	// Check header
	if !strings.Contains(output, "POLICY VIOLATIONS DETECTED - PLEASE FIX") {
		t.Errorf("Expected header in output")
	}

	// Check violation count
	if !strings.Contains(output, "Found 3 policy violation(s)") {
		t.Errorf("Expected violation count in output, got: %s", output)
	}

	// Check file names
	if !strings.Contains(output, "File: main.go") {
		t.Errorf("Expected 'File: main.go' in output")
	}
	if !strings.Contains(output, "File: config.go") {
		t.Errorf("Expected 'File: config.go' in output")
	}

	// Check line numbers
	if !strings.Contains(output, "Line 10:") {
		t.Errorf("Expected 'Line 10:' in output")
	}
	if !strings.Contains(output, "Line 15:") {
		t.Errorf("Expected 'Line 15:' in output")
	}
	if !strings.Contains(output, "Line 5:") {
		t.Errorf("Expected 'Line 5:' in output")
	}

	// Check policy names
	if !strings.Contains(output, "Policy: No hardcoded secrets") {
		t.Errorf("Expected policy name in output")
	}
	if !strings.Contains(output, "Policy: Use environment variables") {
		t.Errorf("Expected policy name in output")
	}

	// Check code snippets
	if !strings.Contains(output, "Code: apiKey := \"sk-1234567890\"") {
		t.Errorf("Expected code snippet in output")
	}

	// Check issue messages
	if !strings.Contains(output, "Issue: Potential hardcoded API key detected") {
		t.Errorf("Expected issue message in output")
	}

	// Check action instruction
	if !strings.Contains(output, "Action: Review and fix this code to comply with the policy.") {
		t.Errorf("Expected action instruction in output")
	}

	// Check footer
	if !strings.Contains(output, "Please fix all violations listed above and ensure the code complies with all policies.") {
		t.Errorf("Expected footer instruction in output")
	}
}

func TestFormatClaudeInstructions_MultipleFilesGroupedAndSorted(t *testing.T) {
	result := &CheckResult{
		Violations: []Violation{
			{
				File:       "z_file.go",
				LineNumber: 20,
				PolicyName: "Policy Z",
				Message:    "Issue Z",
				Code:       "code z",
			},
			{
				File:       "a_file.go",
				LineNumber: 30,
				PolicyName: "Policy A2",
				Message:    "Issue A2",
				Code:       "code a2",
			},
			{
				File:       "a_file.go",
				LineNumber: 10,
				PolicyName: "Policy A1",
				Message:    "Issue A1",
				Code:       "code a1",
			},
		},
		TotalChecked: 50,
	}

	output := FormatClaudeInstructions(result)

	// Files should be sorted alphabetically
	aFileIndex := strings.Index(output, "File: a_file.go")
	zFileIndex := strings.Index(output, "File: z_file.go")

	if aFileIndex == -1 || zFileIndex == -1 {
		t.Errorf("Expected both file names in output")
	}
	if aFileIndex >= zFileIndex {
		t.Errorf("Expected files to be sorted alphabetically (a_file.go before z_file.go)")
	}

	// Within a file, violations should be sorted by line number
	line10Index := strings.Index(output, "Line 10:")
	line30Index := strings.Index(output, "Line 30:")

	if line10Index == -1 || line30Index == -1 {
		t.Errorf("Expected both line numbers in output")
	}
	if line10Index >= line30Index {
		t.Errorf("Expected violations to be sorted by line number (10 before 30)")
	}
}
