package log

import (
	"bytes"
	"regexp"
	"testing"

	logrus "github.com/sirupsen/logrus"
	"github.com/stretchr/testify/require"
)

func TestInitialize(t *testing.T) {
	tests := []struct {
		name         string
		opts         []LoggerOption
		wantErr      bool
		regexps      []*regexp.Regexp
		infoMessage  string
		debugMessage string
	}{
		{
			name: "trivial",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^$`),
			},
		},
		{
			name:        "simple",
			infoMessage: "Hello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=Hello`),
			},
		},
		{
			name: "simple-json",
			opts: []LoggerOption{
				WithFormatter("json"),
			},
			infoMessage: "Hello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^{"level":"info","msg":"Hello"`),
			},
		},
		{
			name: "simple-text",
			opts: []LoggerOption{
				WithFormatter("text"),
			},
			infoMessage: "Hello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=Hello`),
			},
		},
		{
			name: "invalid-formatter",
			opts: []LoggerOption{
				WithFormatter("rubbish"),
			},
			infoMessage: "Hello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=warning.*msg="unknown logging format rubbish, ignoring option"`),
				regexp.MustCompile(`(?m)^time=.*level=info.*msg=Hello`),
			},
		},
		{
			name: "loglevel-below-threshold",
			opts: []LoggerOption{
				WithLogLevel("info"),
			},
			debugMessage: "Hello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^$`),
			},
		},
		{
			name: "loglevel-at-threshold",
			opts: []LoggerOption{
				WithLogLevel("info"),
			},
			infoMessage:  "InfoHello",
			debugMessage: "DebugHello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=InfoHello\n$`),
			},
		},
		{
			name: "invalid-threshold",
			opts: []LoggerOption{
				WithLogLevel("garbage"),
			},
			infoMessage:  "InfoHello",
			debugMessage: "DebugHello",

			regexps: []*regexp.Regexp{
				regexp.MustCompile(`level=warning msg="unknown log level, ignoring option`),
				regexp.MustCompile(`(?m)^time=.*level=info.*msg=InfoHello\n$`),
			},
		},
		{
			name: "invalid-threshold-json-format",
			opts: []LoggerOption{
				WithFormatter("json"),
				WithLogLevel("garbage"),
			},
			infoMessage:  "InfoHello",
			debugMessage: "DebugHello",

			regexps: []*regexp.Regexp{
				regexp.MustCompile(`"msg":"unknown log level, ignoring option: not a valid logrus Level`),
				regexp.MustCompile(`"msg":"InfoHello"`),
			},
		},
		{
			name: "emit-to-stderr",
			opts: []LoggerOption{
				WithOutputName("stderr"),
			},
			infoMessage: "InfoHello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=InfoHello\n$`),
			},
		},
		{
			name: "emit-to-stdout",
			opts: []LoggerOption{
				WithOutputName("stdout"),
			},
			infoMessage: "InfoHello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=InfoHello\n$`),
			},
		},
		{
			name: "emit-to-file",
			opts: []LoggerOption{
				WithOutputName("/tmp/test.log"),
			},
			infoMessage: "InfoHello",
			regexps: []*regexp.Regexp{
				regexp.MustCompile(`^time=.*level=info.*msg=InfoHello\n$`),
			},
		},
		{
			name: "color",
			opts: []LoggerOption{
				WithFormatter("color"),
			},
			infoMessage: "It's starting to look like a triple rainbow.",
			regexps: []*regexp.Regexp{
				regexp.MustCompile("^\x1b\\[36mINFO\x1b\\[0m\\[0000\\] It's starting to look like a triple rainbow."),
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var buf bytes.Buffer

			opts := append([]LoggerOption{}, tt.opts...)
			opts = append(opts, WithWriter(&buf))

			closer, err := Initialize(opts...)
			defer closer.Close()

			if tt.infoMessage != "" {
				logrus.Info(tt.infoMessage)
			}

			if tt.debugMessage != "" {
				logrus.Debug(tt.debugMessage)
			}

			if tt.wantErr {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
			}

			bytes := buf.Bytes()
			for _, re := range tt.regexps {
				require.Regexp(t, re, string(bytes))
			}
		})
	}
}
