//go:build gitgo
// +build gitgo

package sync

import (
	"io/ioutil"
	"log"
	"os"
	"path"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/config"
	"github.com/go-git/go-git/v5/plumbing/transport/ssh"
)

// GitImporter implements an Importer, where files to imports are located
// inside a local directory from your filesystem, backed by git.
type GitImporter struct {
	li     LocalImporter
	Remote string
	Auth   ssh.AuthMethod
}

func NewGitImporter(li LocalImporter, remote string) GitImporter {
	var auth ssh.AuthMethod

	// If there is no ssh-agent setup, try to use a default ssh key
	if _, exists := os.LookupEnv("SSH_AUTH_SOCK"); !exists {
		if home, exists := os.LookupEnv("HOME"); exists {
			for _, d := range []string{"id_fic", "id_ed25519", "id_rsa"} {
				pemBytes, err := ioutil.ReadFile(path.Join(home, ".ssh", d))
				if err == nil {
					log.Println("[GitImporter] Using", path.Join(home, ".ssh", d), "as ssh key to sync repository")
					auth, err = ssh.NewPublicKeys("git", pemBytes, "")
					if ccfg, err := auth.ClientConfig(); err != nil {
						if hkc, err := ssh.NewKnownHostsCallback(); err != nil {
							ccfg.HostKeyCallback = hkc
						}
					}
					break
				}
			}
		}
	}

	return GitImporter{
		li:     li,
		Remote: remote,
		Auth:   auth,
	}
}

func (i GitImporter) Id() *string {
	var gitinfo string
	r, err := git.PlainOpen(i.li.Base)
	if err == nil {
		ref, err := r.Head()
		if err == nil {
			gitinfo = ref.Hash().String()
		}
	}

	return &gitinfo
}

func (i GitImporter) Init() error {
	// Check if the directory exists, create it if needed
	if err := i.li.Init(); err != nil {
		return err
	}

	// If the directory is empty, clone it
	if n, err := countFileInDir(i.li.Base); err != nil {
		return err
	} else if n == 0 {
		_, err = git.PlainClone(i.li.Base, false, &git.CloneOptions{
			URL:               i.Remote,
			RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
			Auth:              i.Auth,
		})
		if err != nil {
			return err
		}
	}

	// Check if the .git directory exists, change the origin remote to our
	r, err := git.PlainOpen(i.li.Base)
	if err != nil {
		return err
	}

	r.DeleteRemote("origin")
	_, err = r.CreateRemote(&config.RemoteConfig{
		Name: "origin",
		URLs: []string{i.Remote},
	})
	if err != nil {
		return err
	}

	return nil
}

func (i GitImporter) Sync() error {
	r, err := git.PlainOpen(i.li.Base)
	if err != nil {
		return err
	}

	w, err := r.Worktree()
	if err != nil {
		return err
	}

	// Perform a git pull --rebase origin/master
	err = w.Pull(&git.PullOptions{
		RemoteName:        "origin",
		Depth:             1,
		RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
		Force:             true,
		Auth:              i.Auth,
	})
	return err
}
