package create

import (
	"bytes"
	"regexp"
	"testing"

	"github.com/MakeNowJust/heredoc"
	"github.com/stretchr/testify/assert"
)

func Test_Write(t *testing.T) {
	type input struct {
		in   []string
		re   *regexp.Regexp
		repl string
	}
	type output struct {
		wantsErr bool
		out      string
		length   int
	}
	tests := []struct {
		name   string
		input  input
		output output
	}{
		{
			name: "single line input",
			input: input{
				in:   []string{"some input line that has wrong information"},
				re:   regexp.MustCompile("wrong"),
				repl: "right",
			},
			output: output{
				wantsErr: false,
				out:      "some input line that has right information",
				length:   42,
			},
		},
		{
			name: "multiple line input",
			input: input{
				in:   []string{"multiple lines\nin this\ninput lines"},
				re:   regexp.MustCompile("lines"),
				repl: "tests",
			},
			output: output{
				wantsErr: false,
				out:      "multiple tests\nin this\ninput tests",
				length:   34,
			},
		},
		{
			name: "no matches",
			input: input{
				in:   []string{"this line has no matches"},
				re:   regexp.MustCompile("wrong"),
				repl: "right",
			},
			output: output{
				wantsErr: false,
				out:      "this line has no matches",
				length:   24,
			},
		},
		{
			name: "no output",
			input: input{
				in:   []string{"remove this whole line"},
				re:   regexp.MustCompile("^remove.*$"),
				repl: "",
			},
			output: output{
				wantsErr: false,
				out:      "",
				length:   22,
			},
		},
		{
			name: "no input",
			input: input{
				in:   []string{""},
				re:   regexp.MustCompile("remove"),
				repl: "",
			},
			output: output{
				wantsErr: false,
				out:      "",
				length:   0,
			},
		},
		{
			name: "multiple lines removed",
			input: input{
				in:   []string{"beginning line\nremove this whole line\nremove this one also\nnot this one"},
				re:   regexp.MustCompile("(?s)^remove.*$"),
				repl: "",
			},
			output: output{
				wantsErr: false,
				out:      "beginning line\nnot this one",
				length:   71,
			},
		},
		{
			name: "removes remote from git push output",
			input: input{
				in: []string{heredoc.Doc(`
					output: some information
					remote:
					remote: Create a pull request for 'regex' on GitHub by visiting:
					remote:      https://github.com/owner/repo/pull/new/regex
					remote:
					output: more information
			 `)},
				re:   regexp.MustCompile("^remote: (Create a pull request.*by visiting|[[:space:]]*https://.*/pull/new/).*\n?$"),
				repl: "",
			},
			output: output{
				wantsErr: false,
				out:      "output: some information\nremote:\nremote:\noutput: more information\n",
				length:   189,
			},
		},
		{
			name: "multiple writes",
			input: input{
				in:   []string{"first write\n", "second write ", "third write"},
				re:   regexp.MustCompile("write"),
				repl: "read",
			},
			output: output{
				wantsErr: false,
				out:      "first read\nsecond read third read",
				length:   36,
			},
		},
	}

	for _, tt := range tests {
		out := &bytes.Buffer{}
		writer := NewRegexpWriter(out, tt.input.re, tt.input.repl)
		t.Run(tt.name, func(t *testing.T) {
			length := 0
			for _, in := range tt.input.in {
				l, err := writer.Write([]byte(in))
				length = length + l
				if tt.output.wantsErr {
					assert.Error(t, err)
					return
				}
				assert.NoError(t, err)
			}
			writer.Flush()
			assert.Equal(t, tt.output.out, out.String())
			assert.Equal(t, tt.output.length, length)
		})
	}
}
