package main

import (
	"bufio"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"testing"

	"code.justin.tv/dta/rockpaperscissors/internal/testutil"
)

func TestURLRegex(t *testing.T) {
	host, name, err := getHostAndNameFromURL("git@git-aws.internal.justin.tv:dta/tcs.git")
	testutil.AssertEquals(t, "host", host, "git-aws.internal.justin.tv")
	testutil.AssertEquals(t, "name", name, "dta/tcs")
	testutil.AssertNil(t, "getHostAndNameFromURL return err", err)

	host, name, err = getHostAndNameFromURL("git+ssh://git@git-aws.internal.justin.tv/systems/plucker.git")
	testutil.AssertEquals(t, "host", host, "git-aws.internal.justin.tv")
	testutil.AssertEquals(t, "name", name, "systems/plucker")
	testutil.AssertNil(t, "getHostAndNameFromURL return err", err)

	host, name, err = getHostAndNameFromURL("https://git-aws.internal.justin.tv/dta/rockpaperscissors.git")
	testutil.AssertEquals(t, "host", host, "git-aws.internal.justin.tv")
	testutil.AssertEquals(t, "name", name, "dta/rockpaperscissors")
	testutil.AssertNil(t, "getHostAndNameFromURL return err", err)

	host, name, err = getHostAndNameFromURL("https://git-aws.internal.justin.tv/dta/rockpaperscissors")
	testutil.AssertEquals(t, "host", host, "git-aws.internal.justin.tv")
	testutil.AssertEquals(t, "name", name, "dta/rockpaperscissors")
	testutil.AssertNil(t, "getHostAndNameFromURL return err", err)

	host, name, err = getHostAndNameFromURL("http://git-aws.internal.justin.tv/dta/rockpaperscissors.git")
	testutil.AssertEquals(t, "host", host, "git-aws.internal.justin.tv")
	testutil.AssertEquals(t, "name", name, "dta/rockpaperscissors")
	testutil.AssertNil(t, "getHostAndNameFromURL return err", err)
}

func countGitRevisions(t *testing.T, filename string) int {
	cmd := exec.Command("git", "rev-list", "HEAD", "--", filename)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		t.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}

	scanner := bufio.NewScanner(stdout)
	lines := 0
	for scanner.Scan() {
		lines++
	}
	if err := scanner.Err(); err != nil {
		t.Fatal(err)
	}

	if err := cmd.Wait(); err != nil {
		t.Fatal(err)
	}

	return lines
}

func simpleExec(t *testing.T, name string, arg ...string) {
	err := exec.Command(name, arg...).Run()
	if err != nil {
		if eerr, ok := err.(*exec.ExitError); ok {
			t.Fatalf("Error running %v %#v (%v):\n%s", name, arg, err, eerr.Stderr)
		}
		t.Fatal(err)
	}
}

func TestGitCommitFileLocally(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestGitCommitFileLocally")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err = os.RemoveAll(dir) // clean up
		if err != nil {
			log.Println(err)
		}
	}()

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

	simpleExec(t, "git", "init")
	// example.com is reserved by the IETF for things like this.
	simpleExec(t, "git", "config", "user.email", "nobody@example.com")
	simpleExec(t, "git", "config", "user.name", "Nobody")
	simpleExec(t, "git", "commit", "--allow-empty", "--quiet", "-m", "Initial commit")

	blueprintFilepath := "project.blueprint"
	err = ioutil.WriteFile(blueprintFilepath, []byte("first version"), 0664)
	if err != nil {
		t.Fatal(err)
	}

	err = gitCommitFileLocally(blueprintFilepath, "First commit: new file")
	testutil.AssertNil(t, "gitCommitFileLocally return err", err)
	testutil.AssertEquals(t, "git revisions", countGitRevisions(t, blueprintFilepath), 1)

	err = gitCommitFileLocally(blueprintFilepath, "No commit: unchanged file")
	testutil.AssertNil(t, "gitCommitFileLocally return err", err)
	testutil.AssertEquals(t, "git revisions", countGitRevisions(t, blueprintFilepath), 1)

	err = ioutil.WriteFile(blueprintFilepath, []byte("second version"), 0664)
	if err != nil {
		t.Fatal(err)
	}

	err = gitCommitFileLocally(blueprintFilepath, "Second commit: changed file")
	testutil.AssertNil(t, "gitCommitFileLocally return err", err)
	testutil.AssertEquals(t, "git revisions", countGitRevisions(t, blueprintFilepath), 2)
}
