package matcher_test

import (
	"fmt"
	"testing"

	"git.max-richter.dev/max/marka/parser/matcher"
	"git.max-richter.dev/max/marka/registry"
	"git.max-richter.dev/max/marka/template"
	"git.max-richter.dev/max/marka/testdata"
)

func TestMatch_FuzzyFindAll(t *testing.T) {
	recipeMd := testdata.Read(t, "baguette/input.md")

	tests := []struct {
		Needle                 string
		Start, End, StartIndex int
	}{
		{StartIndex: 0, Needle: "## Ingredients\n", Start: 90, End: 105},
		{StartIndex: 0, Needle: "## Ingrdients\n", Start: 90, End: 105},
		{StartIndex: 0, Needle: "## Inrdients\n", Start: 90, End: 105},
		{StartIndex: 0, Needle: "---\n", Start: 0, End: 4},
		{StartIndex: 4, Needle: "---\n", Start: 43, End: 47},
		{StartIndex: 0, Needle: "## Steps\n", Start: 129, End: 138},
		{StartIndex: 0, Needle: "## Stps\n", Start: 129, End: 138},
		{StartIndex: 0, Needle: "## Step\n", Start: 129, End: 138},
	}

	for _, test := range tests {
		start, end := matcher.FuzzyFind(string(recipeMd), test.StartIndex, test.Needle, 0.3) // allow 50% error

		if start != test.Start || end != test.End {
			t.Errorf("Start or end do not match: Needle=%q Start=%d/%d End=%d/%d", test.Needle, test.Start, start, test.End, end)
		}
	}
}

func TestMatch_FuzzyBlockBaguette(t *testing.T) {
	recipeMd := testdata.Read(t, "baguette/input.md")
	schemaMd, err := registry.GetTemplate("Recipe")
	if err != nil {
		t.Errorf("Failed to load template: %s", err.Error())
		t.FailNow()
	}

	blocks, err := template.CompileTemplate(schemaMd)
	if err != nil {
		t.Errorf("Failed to compile template: %s", err.Error())
		t.FailNow()
	}

	matches := matcher.MatchBlocksFuzzy(string(recipeMd), blocks, 0.3)

	for _, m := range matches {
		fmt.Printf("Content: '%s'->'%q'\n\n", m.Block.Path, m.GetContent())
	}

	expected := []struct {
		value string
	}{
		{
			value: "_type: Recipe\nauthor.name: Max Richter",
		},
		{
			value: "Baguette",
		},
		{
			value: "My favourite baguette recipe",
		},
		{
			value: "- Flour\n- Water\n- Salt",
		},
		{
			value: "1. Mix Flour Water and Salt\n2. Bake the bread",
		},
	}

	for i, m := range matches {
		if i > len(expected)-1 {
			t.Errorf("No expected result for match: %d -> %q", i, m.GetContent())
			t.FailNow()
		}
		if expected[i].value != m.GetContent() {
			t.Errorf("Match %d did not match expected: %q", i, expected[i].value)
		}
	}
}

func TestMatch_FuzzyBlockSalad(t *testing.T) {
	recipeMd := testdata.Read(t, "recipe_salad/input.md")
	schemaMd, err := registry.GetTemplate("Recipe")
	if err != nil {
		t.Errorf("Failed to load template: %s", err.Error())
		t.FailNow()
	}
	blocks, err := template.CompileTemplate(schemaMd)
	if err != nil {
		t.Errorf("failed to compile template: %s", err.Error())
		t.FailNow()
	}

	matches := matcher.MatchBlocksFuzzy(string(recipeMd), blocks, 0.3)

	expected := []struct {
		value string
	}{
		{
			value: "_type: Recipe\nauthor.name: Alex Chef\ncookTime: PT0M\nimage: https://example.com/salad.jpg\nprepTime: PT10M\nrecipeYield: 2 servings",
		},
		{
			value: "Simple Salad",
		},
		{
			value: "A quick green salad.",
		},
		{
			value: "- 100 g lettuce\n- 5 cherry tomatoes\n- 1 tbsp olive oil\n- Pinch of salt",
		},
		{
			value: "1. Wash and dry the lettuce.\n2. Halve the cherry tomatoes.\n3. Toss with olive oil and salt.",
		},
	}

	for i, m := range matches {

		if i > len(expected)-1 {
			t.Errorf("No expected result for match: %d -> %q", i, m.GetContent())
			t.FailNow()
		}
		if expected[i].value != m.GetContent() {
			t.Errorf("Match %d did not match expected: %q", i, m.GetContent())
		}
		fmt.Printf("match: %s->%q\n", m.Block.Path, m.GetContent())
	}
}
