package importer

import (
	"bytes"
	"os"
	"strings"
	"testing"
)

func loadFixture(t *testing.T, name string) []byte {
	t.Helper()
	data, err := os.ReadFile("testdata/" + name)
	if err != nil {
		t.Fatalf("read fixture %s: %v", name, err)
	}
	return data
}

func TestGitleaksImporter_Name(t *testing.T) {
	if (GitleaksImporter{}).Name() != "gitleaks" {
		t.Errorf("GitleaksImporter.Name() = %q, want %q", (GitleaksImporter{}).Name(), "gitleaks")
	}
	if (GitleaksCSVImporter{}).Name() != "gitleaks-csv" {
		t.Errorf("GitleaksCSVImporter.Name() = %q, want %q", (GitleaksCSVImporter{}).Name(), "gitleaks-csv")
	}
}

func TestGitleaksImporter_JSON(t *testing.T) {
	data := loadFixture(t, "gitleaks-sample.json")
	findings, err := (GitleaksImporter{}).Import(bytes.NewReader(data))
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	if len(findings) != 3 {
		t.Fatalf("expected 3 findings, got %d", len(findings))
	}
	if findings[0].ProviderName != "openai" {
		t.Errorf("findings[0].ProviderName = %q, want %q", findings[0].ProviderName, "openai")
	}
	if findings[0].KeyValue != "sk-proj-1234567890abcdef1234" {
		t.Errorf("findings[0].KeyValue mismatch: %q", findings[0].KeyValue)
	}
	if findings[0].Source != "config/app.yml" {
		t.Errorf("findings[0].Source = %q", findings[0].Source)
	}
	if findings[0].LineNumber != 12 {
		t.Errorf("findings[0].LineNumber = %d, want 12", findings[0].LineNumber)
	}
	if findings[0].SourceType != "import:gitleaks" {
		t.Errorf("findings[0].SourceType = %q", findings[0].SourceType)
	}
	if findings[0].Confidence != "medium" {
		t.Errorf("findings[0].Confidence = %q, want medium", findings[0].Confidence)
	}
	if findings[0].VerifyStatus != "unverified" {
		t.Errorf("findings[0].VerifyStatus = %q, want unverified", findings[0].VerifyStatus)
	}
	if findings[0].Verified {
		t.Errorf("findings[0].Verified should be false")
	}
	if findings[0].KeyMasked == "" {
		t.Errorf("findings[0].KeyMasked should be set")
	}
	if findings[1].ProviderName != "aws" {
		t.Errorf("findings[1].ProviderName = %q, want aws", findings[1].ProviderName)
	}
	if findings[1].LineNumber != 55 {
		t.Errorf("findings[1].LineNumber = %d, want 55", findings[1].LineNumber)
	}
	if findings[2].ProviderName != "generic" {
		t.Errorf("findings[2].ProviderName = %q, want generic", findings[2].ProviderName)
	}
}

func TestGitleaksImporter_CSV(t *testing.T) {
	data := loadFixture(t, "gitleaks-sample.csv")
	findings, err := (GitleaksCSVImporter{}).Import(bytes.NewReader(data))
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	if len(findings) != 3 {
		t.Fatalf("expected 3 findings, got %d", len(findings))
	}
	if findings[0].ProviderName != "openai" {
		t.Errorf("findings[0].ProviderName = %q, want openai", findings[0].ProviderName)
	}
	if findings[0].KeyValue != "sk-proj-1234567890abcdef1234" {
		t.Errorf("findings[0].KeyValue = %q", findings[0].KeyValue)
	}
	if findings[0].Source != "config/app.yml" {
		t.Errorf("findings[0].Source = %q", findings[0].Source)
	}
	if findings[0].LineNumber != 12 {
		t.Errorf("findings[0].LineNumber = %d, want 12", findings[0].LineNumber)
	}
	if findings[1].ProviderName != "aws" {
		t.Errorf("findings[1].ProviderName = %q, want aws", findings[1].ProviderName)
	}
	if findings[2].ProviderName != "generic" {
		t.Errorf("findings[2].ProviderName = %q, want generic", findings[2].ProviderName)
	}
}

func TestGitleaksImporter_NormalizeRuleID(t *testing.T) {
	cases := []struct{ in, out string }{
		{"openai-api-key", "openai"},
		{"aws-access-token", "aws"},
		{"anthropic-api-key", "anthropic"},
		{"generic-api-key", "generic"},
		{"github-pat", "github-pat"},
		{"Some-Secret", "some"},
		{"AWS-Access-Token", "aws"},
	}
	for _, c := range cases {
		got := normalizeGitleaksRuleID(c.in)
		if got != c.out {
			t.Errorf("normalizeGitleaksRuleID(%q) = %q, want %q", c.in, got, c.out)
		}
	}
}

func TestGitleaksImporter_EmptyArray(t *testing.T) {
	findings, err := (GitleaksImporter{}).Import(strings.NewReader("[]"))
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	if len(findings) != 0 {
		t.Errorf("expected 0 findings, got %d", len(findings))
	}
}

func TestGitleaksImporter_EmptyCSV(t *testing.T) {
	header := "RuleID,Commit,File,SymlinkFile,Secret,Match,StartLine,EndLine,StartColumn,EndColumn,Author,Message,Date,Email,Fingerprint,Tags\n"
	findings, err := (GitleaksCSVImporter{}).Import(strings.NewReader(header))
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	if len(findings) != 0 {
		t.Errorf("expected 0 findings, got %d", len(findings))
	}
}

func TestGitleaksImporter_InvalidJSON(t *testing.T) {
	_, err := (GitleaksImporter{}).Import(strings.NewReader("{not json"))
	if err == nil {
		t.Errorf("expected error for invalid JSON")
	}
}

func TestGitleaksImporter_SymlinkFallback(t *testing.T) {
	jsonInput := `[{"RuleID":"openai-api-key","Secret":"sk-proj-1234567890abcdef1234","File":"","SymlinkFile":"link/config.yml","StartLine":1}]`
	findings, err := (GitleaksImporter{}).Import(strings.NewReader(jsonInput))
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	if len(findings) != 1 || findings[0].Source != "link/config.yml" {
		t.Errorf("expected symlink fallback source, got %+v", findings)
	}
}
