package scanning

import (
	"regexp"
	"testing"
)

func TestPatternsCompile(t *testing.T) {
	for _, p := range Patterns {
		_, err := regexp.Compile(p.Raw)
		if err != nil {
			t.Errorf("pattern %q failed to compile: %v", p.Name, err)
		}
	}
}

func TestPatternsHaveNames(t *testing.T) {
	for _, p := range Patterns {
		if p.Name == "" {
			t.Error("pattern with empty name")
		}
		if p.Description == "" {
			t.Errorf("pattern %q has empty description", p.Name)
		}
		if p.Severity != "high" && p.Severity != "medium" && p.Severity != "low" {
			t.Errorf("pattern %q has invalid severity %q", p.Name, p.Severity)
		}
	}
}

func TestAWSAccessKey(t *testing.T) {
	re := regexp.MustCompile(`AKIA[0-9A-Z]{16}`)
	cases := []struct {
		input string
		match bool
	}{
		{"AKIAIOSFODNN7EXAMPLE", true},
		{"AKIA1234567890123456", true},
		{"not-a-key", false},
		{"SKIA1234567890123456", false},
	}
	for _, tc := range cases {
		got := re.MatchString(tc.input)
		if got != tc.match {
			t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match)
		}
	}
}

func TestGitHubToken(t *testing.T) {
	re := regexp.MustCompile(`gh[pousr]_[A-Za-z0-9_]{36,}`)
	cases := []struct {
		input string
		match bool
	}{
		{"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true},
		{"gho_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true},
		{"ghu_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true},
		{"ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true},
		{"ghr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true},
		{"not-a-token", false},
		{"ghp_short", false},
	}
	for _, tc := range cases {
		got := re.MatchString(tc.input)
		if got != tc.match {
			t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match)
		}
	}
}

func TestPrivateKey(t *testing.T) {
	re := regexp.MustCompile(`-----BEGIN\s+(RSA|EC|OPENSSH|DSA|PRIVATE)(\s+PRIVATE)?\s+KEY-----`)
	cases := []struct {
		input string
		match bool
	}{
		{"-----BEGIN RSA PRIVATE KEY-----", true},
		{"-----BEGIN EC PRIVATE KEY-----", true},
		{"-----BEGIN OPENSSH PRIVATE KEY-----", true},
		{"-----BEGIN DSA PRIVATE KEY-----", true},
		{"-----BEGIN PRIVATE KEY-----", true},
		{"-----BEGIN CERTIFICATE-----", false},
		{"public key is here", false},
	}
	for _, tc := range cases {
		got := re.MatchString(tc.input)
		if got != tc.match {
			t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match)
		}
	}
}

func TestJWT(t *testing.T) {
	re := regexp.MustCompile(`eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}`)
	cases := []struct {
		input string
		match bool
	}{
		{"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNnZctV9XjvP_oGZQZxGdAqVxQ", true},
		{"not-a-jwt", false},
	}
	for _, tc := range cases {
		got := re.MatchString(tc.input)
		if got != tc.match {
			t.Errorf("input %q: got %v, want %v", tc.input, got, tc.match)
		}
	}
}

func TestTruncate(t *testing.T) {
	if truncate("hello", 10) != "hello" {
		t.Error("should not truncate short strings")
	}
	if truncate("hello world this is long", 10) != "hello worl..." {
		t.Errorf("got %q", truncate("hello world this is long", 10))
	}
}
