package scheduler

import (
	"bytes"
	"io/ioutil"
	"local/firestormy/config"
	"local/storage"
	"os"
	"testing"
)

func TestSchedulerAddRemove(t *testing.T) {
	config.Store, _ = storage.New(storage.MAP)
	s := New()
	j, err := NewJob(Bash, "@hourly", "hostname")
	if err != nil {
		t.Fatal(err)
	}
	if err := s.Add(j); err != nil {
		t.Fatal(err)
	}
	if list, err := s.List(); err != nil {
		t.Fatal(err)
	} else if len(list) != 1 {
		t.Fatal(err)
	}
	if err := s.Remove(j); err != nil {
		t.Fatal(err)
	}
	if list, err := s.List(); err != nil {
		t.Fatal(err)
	} else if len(list) != 0 {
		t.Fatal(err)
	}
}

func TestSchedulerStartStop(t *testing.T) {
	b, clean := captureLog()
	defer clean()
	config.Store, _ = storage.New(storage.MAP)

	s := New()
	for i := 0; i < 5; i++ {
		j, err := NewJob(Bash, "* * * * *", "hostname")
		if err != nil {
			t.Fatal(err)
		}
		if err := s.Add(j); err != nil {
			t.Fatal(err)
		}
	}

	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	if err := s.Stop(); err != nil {
		t.Fatal(err)
	}

	if n := bytes.Count(b.Bytes(), []byte("schedule")); n != 5 {
		t.Errorf("%v: %s", n, b.Bytes())
	}
}

func TestSchedulerFromFile(t *testing.T) {
	was := config.Store
	defer func() {
		config.Store = was
	}()
	cases := map[string]struct {
		content string
		want    int
	}{
		"just a job": {
			content: `10 */12 * * * /bin/bash -c "hostname"`,
			want:    1,
		},
		"just a job with seconds": {
			content: `*/2 10 */12 * * * /bin/bash -c "hostname"`,
			want:    1,
		},
		"all wild": {
			content: `* * * * * /bin/bash -c "hostname"`,
			want:    1,
		},
		"all single numbers": {
			content: `1 1 1 1 1 /bin/bash -c "hostname"`,
			want:    1,
		},
		"all double numbers": {
			content: `10 10 10 10 2 /bin/bash -c "hostname"`,
			want:    1,
		},
		"all /\\d+": {
			content: `*/11 */2 */3 */4 */1 /bin/bash -c "hostname"`,
			want:    1,
		},
		"2 jobs with 1 comment no whitespace leading": {
			content: `# this is my comment
            10 */12 * * * /bin/bash -c "hostname"
            10 */12 * * * /bin/bash -c "hostname"
         `,
			want: 2,
		},
		"2 jobs with 1 comment whitespace leading": {
			content: `   # this is my comment
            10 */12 * * * /bin/bash -c "hostname"
            10 */12 * * * /bin/bash -c "hostname"
         `,
			want: 2,
		},
		"2 jobs with crazy whitespace between cron spec": {
			content: `   # this is my comment
            10     */12 * * * /bin/bash -c "hostname"
            10 */12     *     * * /bin/bash -c "hostname"
         `,
			want: 2,
		},
		"2 jobs with 2 comemnts and 2 empty lines": {
			content: `   # this is my comment

            # this is a second comment
            10     */12 * * * /bin/bash -c "hostname"

            10 */12     *     * * /bin/bash -c "hostname"
         `,
			want: 2,
		},
	}

	for name, c := range cases {
		t.Run(name, func(t *testing.T) {
			config.Store, _ = storage.New(storage.MAP)
			f, err := ioutil.TempFile(os.TempDir(), "testSchedulerFromFile")
			if err != nil {
				t.Fatal(err)
			}
			defer os.Remove(f.Name())
			f.Write([]byte(c.content))
			f.Close()

			s, err := NewFromFile(f.Name())
			if err != nil {
				t.Fatal(err)
			}
			jobs, err := s.List()
			if err != nil {
				t.Fatal(err)
			}
			if len(jobs) != c.want {
				t.Fatalf("want %v, got %v jobs", c.want, jobs)
			}
		})
	}
}
