package logs

import (
	"os"
	"path/filepath"
	"testing"
	"time"

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

var logTime time.Time

func init() {
	logTime, _ = time.Parse(LogTimeFormat, "2023-08-07T19:56:34.223758260-06:00")
}

func makeTestLogLine(typ, msg string) *LogLine {
	return &LogLine{
		Device:       "stdout",
		ParseLogType: typ,
		Msg:          msg,
		Time:         logTime,
	}
}

func TestGetTailLog(t *testing.T) {
	tests := []struct {
		name        string
		fileContent string
		tail        int
		want        []*LogLine
	}{
		{
			name: "simple tail",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout F line2
2023-08-07T19:56:34.223758260-06:00 stdout F line3
`,
			tail: 2,
			want: []*LogLine{makeTestLogLine("F", "line2"), makeTestLogLine("F", "line3")},
		},
		{
			name: "simple tail with more tail than lines",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout F line2
2023-08-07T19:56:34.223758260-06:00 stdout F line3
`,
			tail: 10,
			want: []*LogLine{makeTestLogLine("F", "line1"), makeTestLogLine("F", "line2"), makeTestLogLine("F", "line3")},
		},
		{
			name: "tail with partial logs",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout P lin
2023-08-07T19:56:34.223758260-06:00 stdout F e2
2023-08-07T19:56:34.223758260-06:00 stdout F line3
`,
			tail: 2,
			want: []*LogLine{makeTestLogLine("P", "lin"), makeTestLogLine("F", "e2"), makeTestLogLine("F", "line3")},
		},
		{
			name: "tail with partial logs and more than lines",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout P lin
2023-08-07T19:56:34.223758260-06:00 stdout F e2
2023-08-07T19:56:34.223758260-06:00 stdout F line3
`,
			tail: 10,
			want: []*LogLine{makeTestLogLine("F", "line1"), makeTestLogLine("P", "lin"), makeTestLogLine("F", "e2"), makeTestLogLine("F", "line3")},
		},
		{
			name: "multiple partial lines in a row",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout P l
2023-08-07T19:56:34.223758260-06:00 stdout P i
2023-08-07T19:56:34.223758260-06:00 stdout P n
2023-08-07T19:56:34.223758260-06:00 stdout P e
2023-08-07T19:56:34.223758260-06:00 stdout F 2
2023-08-07T19:56:34.223758260-06:00 stdout F line3
`,
			tail: 2,
			want: []*LogLine{makeTestLogLine("P", "l"), makeTestLogLine("P", "i"), makeTestLogLine("P", "n"),
				makeTestLogLine("P", "e"), makeTestLogLine("F", "2"), makeTestLogLine("F", "line3")},
		},
		{
			name: "partial line at the end",
			fileContent: `2023-08-07T19:56:34.223758260-06:00 stdout F line1
2023-08-07T19:56:34.223758260-06:00 stdout P lin
`,
			tail: 1,
			want: []*LogLine{makeTestLogLine("P", "lin")},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dir := t.TempDir()
			file := filepath.Join(dir, "log")
			f, err := os.Create(file)
			assert.NoError(t, err, "create log file")
			_, err = f.WriteString(tt.fileContent)
			assert.NoError(t, err, "write log file")
			f.Close()
			got, err := getTailLog(file, tt.tail)
			assert.NoError(t, err, "getTailLog()")
			assert.Equal(t, tt.want, got, "log lines")
		})
	}
}

func TestGetTailLogBigFiles(t *testing.T) {
	dir := t.TempDir()
	file := filepath.Join(dir, "log")
	f, err := os.Create(file)
	assert.NoError(t, err, "create log file")
	want := make([]*LogLine, 0, 2000)
	for i := 0; i < 1000; i++ {
		_, err = f.WriteString(`2023-08-07T19:56:34.223758260-06:00 stdout P lin
2023-08-07T19:56:34.223758260-06:00 stdout F e2
`)
		assert.NoError(t, err, "write log file")
		want = append(want, makeTestLogLine("P", "lin"), makeTestLogLine("F", "e2"))
	}
	f.Close()

	// try a big tail greater than the lines
	got, err := getTailLog(file, 5000)
	assert.NoError(t, err, "getTailLog()")
	assert.Equal(t, want, got, "all log lines")

	// try a smaller than lines tail
	got, err = getTailLog(file, 100)
	assert.NoError(t, err, "getTailLog()")
	// this will return the last 200 lines because of partial + full and we only count full lines for tail.
	assert.Equal(t, want[1800:2000], got, "tail 100 log lines")
}
