package log

import (
	"io/ioutil"
	"os"
	"testing"

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

func assertFileNotExists(t *testing.T, fn string) {
	t.Helper()
	_, err := os.Stat(fn)
	if err == nil {
		t.Errorf("file should not exists")
	} else if os.IsNotExist(err) {
		// pass
	} else {
		t.Fatal(err)
	}
}

func assertFileExists(t *testing.T, fn string) {
	t.Helper()
	_, err := os.Stat(fn)
	if err == nil {
		// pass
	} else if os.IsNotExist(err) {
		t.Errorf("file should exists")
	} else {
		t.Fatal(err)
	}
}

func TestFileLogger(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "*")
	defer os.RemoveAll(tempDir)

	if err != nil {
		t.Fatal(err)
	}

	t.Run("Reopen()", func(t *testing.T) {
		t.Run("should ignore if not open", func(t *testing.T) {
			fn := tempDir + "/ReopenCase1"
			l := FileLogger{Filename: fn}

			assert.Nil(t, l.Reopen())
			assertFileNotExists(t, fn)
		})

		t.Run("should close if open", func(t *testing.T) {
			fn := tempDir + "/ReopenCase2"
			l := FileLogger{Filename: fn}

			assert.Nil(t, l.openNew())
			assertFileExists(t, fn)
			assert.Nil(t, l.Reopen())
			assert.Nil(t, l.file, "file should be closed")
		})
	})

	t.Run("Write()", func(t *testing.T) {
		t.Run("should create new file if not exists", func(t *testing.T) {
			fn := tempDir + "/WriteCase1"
			l := FileLogger{Filename: fn}

			assertFileNotExists(t, fn)
			if _, err := l.Write([]byte("foo")); err != nil {
				t.Fatal(err)
			}
			assertFileExists(t, fn)
			assert.Nil(t, l.close())
		})

		t.Run("should use old file if exists", func(t *testing.T) {
			fn := tempDir + "/WriteCase1"
			l := FileLogger{Filename: fn}

			assertFileExists(t, fn)
			if _, err := l.Write([]byte("foo")); err != nil {
				t.Fatal(err)
			}
			assertFileExists(t, fn)
		})

		t.Run("should write correct content for new file", func(t *testing.T) {
			fn := tempDir + "/WriteCase2"
			l := FileLogger{Filename: fn}

			if _, err := l.Write([]byte("foo")); err != nil {
				t.Fatal(err)
			}
			if err := l.Reopen(); err != nil {
				t.Fatal(err)
			}
			bytes, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatal(err)
			}
			assert.Equal(t, "foo", string(bytes), "wrong content")
		})

		t.Run("should append correct content for old file", func(t *testing.T) {
			fn := tempDir + "/WriteCase2"
			l := FileLogger{Filename: fn}

			if _, err := l.Write([]byte("bar")); err != nil {
				t.Fatal(err)
			}
			if err := l.Reopen(); err != nil {
				t.Fatal(err)
			}
			bytes, err := ioutil.ReadFile(fn)
			if err != nil {
				t.Fatal(err)
			}
			assert.Equal(t, "foobar", string(bytes), "wrong content")
		})
	})
}

func TestFileLoggerSet(t *testing.T) {
	t.Run("Reopen", func(t *testing.T) {
		t.Run("should pass with empty loggers", func(t *testing.T) {
			fls := FileLoggers{}
			err := fls.Reopen()
			assert.Nil(t, err)
		})

		t.Run("should pass with loggers", func(t *testing.T) {
			tmpFile1, err := ioutil.TempFile("", "*")
			if err != nil {
				t.Fatal(err)
			}

			defer os.Remove(tmpFile1.Name())

			tmpFile2, err := ioutil.TempFile("", "*")
			if err != nil {
				t.Fatal(err)
			}

			defer os.Remove(tmpFile2.Name())
			logger1 := FileLogger{Filename: tmpFile1.Name()}
			logger2 := FileLogger{Filename: tmpFile2.Name()}

			fls := FileLoggers{
				&logger1,
				&logger2,
			}

			logger1.Write([]byte("foo"))

			err = fls.Reopen()

			assert.Nil(t, err)
		})
	})
}
