package testmark_test

import (
	"os"
	"regexp"
	"strings"
	"testing"

	testmark "github.com/warpfork/go-testmark/v2"
)

func TestDocTestFunctionality(t *testing.T) {
	// Test the DocTest struct creation
	doctest := testmark.DefaultDocTest()
	if doctest == nil {
		t.Fatal("DefaultDocTest returned nil")
	}

	if doctest.PackageTemplate == "" {
		t.Error("PackageTemplate should not be empty")
	}

	if len(doctest.SkipPatterns) == 0 {
		t.Error("Should have default skip patterns")
	}

	// Test code identification
	tests := []struct {
		lang     string
		code     string
		expected bool
	}{
		{"go", "fmt.Println(\"hello\")", true},
		{"golang", "package main", true},
		{"", "package main\nfunc main() {}", true},
		{"", "testmark.NewHunk(\"test\", \"\", \"content\")", true},
		{"", "fmt := \"hello\"", true},
		{"python", "print('hello')", false},
		{"shell", "echo hello", false},
	}

	for _, tt := range tests {
		if got := doctest.IsGoCode(tt.lang, tt.code); got != tt.expected {
			t.Errorf("isGoCode(%q, %q) = %v, want %v", tt.lang, tt.code, got, tt.expected)
		}
	}
}

func TestSkipPatterns(t *testing.T) {
	doctest := testmark.DefaultDocTest()

	// Test skip patterns
	tests := []struct {
		code     string
		expected bool
	}{
		{"// skip this code", true},
		{"// TODO: implement this", true},
		{"func TestSomething(t *testing.T) {}", true},
		{"func ExampleUsage() {}", true},
		{"fmt.Println(\"hello\")", false},
	}

	for _, tt := range tests {
		if got := doctest.ShouldSkip(tt.code); got != tt.expected {
			t.Errorf("ShouldSkip(%q) = %v, want %v", tt.code, got, tt.expected)
		}
	}
}

func TestCodeBlockExtraction(t *testing.T) {
	doctest := testmark.DefaultDocTest()
	markdown := `# Example

Here's some Go code:

` + "```go\npackage main\nfunc main() { fmt.Println(\"hello\") }\n```" + `

And some other code:

` + "```python\nprint('hello')\n```" + `

And another Go block:

` + "```\nfmt.Println(\"implicit go\")\n```" + `
`

	blocks := doctest.ExtractGoCodeBlocks(markdown)
	if len(blocks) != 2 {
		t.Errorf("expected 2 Go code blocks, got %d", len(blocks))
	}

	expected := []string{
		"package main\nfunc main() { fmt.Println(\"hello\") }",
		"fmt.Println(\"implicit go\")",
	}

	for i, block := range blocks {
		if i >= len(expected) {
			break
		}
		if strings.TrimSpace(block) != expected[i] {
			t.Errorf("block %d:\nexpected: %q\ngot:      %q", i, expected[i], strings.TrimSpace(block))
		}
	}
}

func TestSyntaxValidation(t *testing.T) {
	doctest := testmark.DefaultDocTest()

	tests := []struct {
		code  string
		valid bool
	}{
		{"package main\nfunc main() {}", true},
		{"fmt.Println(\"hello\")", false}, // incomplete
		{"package main\nfunc main() { invalid syntax", false},
		{"var x = 42", false}, // incomplete
	}

	for _, tt := range tests {
		if got := doctest.IsValidGoSyntax(tt.code); got != tt.valid {
			t.Errorf("IsValidGoSyntax(%q) = %v, want %v", tt.code, got, tt.valid)
		}
	}
}

func TestCodeWrapping(t *testing.T) {
	doctest := testmark.DefaultDocTest()
	code := "fmt.Println(\"hello\")"
	wrapped := doctest.WrapCode(code)

	if !strings.Contains(wrapped, "package main") {
		t.Error("wrapped code should contain package declaration")
	}
	if !strings.Contains(wrapped, "func main()") {
		t.Error("wrapped code should contain main function")
	}
	if !strings.Contains(wrapped, "fmt.Println") {
		t.Error("wrapped code should contain original code")
	}

	// Test that wrapped code is valid
	if !doctest.IsValidGoSyntax(wrapped) {
		t.Errorf("wrapped code should be valid Go:\n%s", wrapped)
	}
}

func TestConvenienceFunctions(t *testing.T) {
	// We can't easily test the actual file operations without creating temp files,
	// but we can test that the functions exist and don't panic when called with empty FS
	emptyFS := os.DirFS("/nonexistent")

	defer func() {
		if r := recover(); r != nil {
			// Expected to fail due to nonexistent directory, but shouldn't panic
			t.Log("Expected failure for nonexistent directory")
		}
	}()

	// These should not panic, even with empty/invalid FS
	t.Run("TestReadmeExamples", func(t *testing.T) {
		// This will likely fail to find files, but shouldn't panic
		testmark.TestReadmeExamples(t, emptyFS)
	})
}

// Test that we can create custom DocTest configurations
func TestCustomDocTest(t *testing.T) {
	doctest := &testmark.DocTest{
		PackageTemplate: "custom template",
		ImportTemplate:  "custom imports",
		TestTimeout:     "60s",
		SkipPatterns: []*regexp.Regexp{
			regexp.MustCompile("CUSTOM_SKIP"),
		},
	}

	if doctest.PackageTemplate != "custom template" {
		t.Error("custom package template not set")
	}

	if !doctest.ShouldSkip("// CUSTOM_SKIP this code") {
		t.Error("custom skip pattern not working")
	}
}
