package main

import (
	"bytes"
	"slices"
	"strings"
	"testing"
)

func TestSubmodulesParsing(t *testing.T) {
	tests := []struct {
		name      string
		file      string
		subs      []Submodule
		has_error bool
	}{
		{
			name: "Empty submodules file",
			file: "",
			subs: []Submodule{},
		},
		{
			name: "Empty single submodule",
			file: "[submodule \"Foo\"]",
			subs: []Submodule{
				{Name: "Foo"},
			},
		},
		{
			name:      "Invalid submodule name",
			file:      "[submodule \"Foo']",
			has_error: true,
		},
		{
			name:      "Invalid submodule name",
			file:      "[submodule 'Foo']",
			has_error: true,
		},
		{
			name:      "Invalid submodule name",
			file:      "[submodule Foo]",
			has_error: true,
		},
		{
			name:      "Invalid submodule name",
			file:      "[submodul \"Foo\"]",
			has_error: true,
		},
		{
			name:      "Invalid submodule name",
			file:      "[submodule \"Foo\"",
			has_error: true,
		},
		{
			name:      "Gerbage input",
			file:      "asdf kjasf[d;fkl",
			has_error: true,
		},
		{
			name: "Submodule with one entry",
			file: "[submodule \"libfoo\"]\npath = foo\n\n",
			subs: []Submodule{
				{
					Name: "libfoo",
					Path: "foo",
				},
			},
		},
		{
			name: "Submodules with funny entries entries",
			file: "[submodule \"libfoo\"]\npath = foo [ bar  \n\n       [ submodule \"test \"   ]\npath=ma  ma\nurl= safe",
			subs: []Submodule{
				{
					Name: "libfoo",
					Path: "foo [ bar",
				},
				{
					Name: "test ",
					Path: "ma  ma",
					Url:  "safe",
				},
			},
		},
		{
			name: "Submodule with valid entries",
			file: "[submodule \"libfoo\"]\npath=foo\nurl=goo\nupdate=none\nbranch=test\nignore=all\nshallow=true",
			subs: []Submodule{
				{
					Name:    "libfoo",
					Path:    "foo",
					Url:     "goo",
					Update:  "none",
					Branch:  "test",
					Ignore:  "all",
					Shallow: "true",
				},
			},
		},
		{
			name:      "Submodule with an valid entry",
			file:      "[submodule \"libfoo\"]\npath=foo\nurl=goo\nupdate=none\nbranch=test\nignore=all\nshallow=true\nunknown = something",
			has_error: true,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			mods, err := ParseSubmodulesFile(strings.NewReader(test.file))
			if test.has_error {
				if err == nil {
					t.Error("Expected an error")
				}
			} else if err != nil {
				t.Error("unexpected error:", err)
			}
			if !slices.Equal(mods, test.subs) {
				t.Error("expected", test.subs, "but got", mods)
			}
		})
	}
}

func TestSubmodulesWriting(t *testing.T) {
	tests := []struct {
		name      string
		subs      []Submodule
		output    []byte
		has_error bool
	}{
		{
			name:   "empty Submodules",
			output: []byte(""),
		},
		{
			name: "single submodule",
			subs: []Submodule{
				{
					Name: "foo",
					Url:  "bar",
				},
			},
			output: []byte("[submodule \"foo\"]\n\turl = bar\n"),
		},
		{
			name: "empty name submodule",
			subs: []Submodule{
				{
					Name: "foo",
					Url:  "bar",
				},
				{},
			},
			has_error: true,
		},
		{
			name: "submodule with all the things",
			subs: []Submodule{
				{
					Name: "foo",
					Url:  "bar",
				},
				{
					Name: "1",
					Url: "2",
					Update: "ok",
					Path: "3",
					Branch: "4",
					Ignore: "5",
					Shallow: "6",
				},
			},
			output: []byte("[submodule \"foo\"]\n\turl = bar\n[submodule \"1\"]\n\tpath = 3\n\turl = 2\n\tbranch = 4\n\tignore = 5\n\tshallow = 6\n\tupdate = ok\n"),
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			out := bytes.Buffer{}
			if err := WriteSubmodules(test.subs, &out); err != nil {
				if !test.has_error {
					t.Error(err)
				}
				return
			}
			if test.has_error {
				t.Error("expected an error")
			}
			if !slices.Equal(out.Bytes(), test.output) {
				t.Error("expected:", test.output, "but got:", out.Bytes())
			}
		})
	}
}
