// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cache

import (
	"bytes"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"time"

	git "github.com/libgit2/git2go"
)

// gitCache manages a set of bare git repositories.
type gitCache struct {
	// directory to hold the repositories.
	dir string

	// Directory to store log files for fetches and clones.
	logDir string
}

// newGitCache constructs a gitCache object.
func newGitCache(baseDir string, opts Options) (*gitCache, error) {
	c := gitCache{
		dir:    filepath.Join(baseDir),
		logDir: filepath.Join(baseDir, "slothfs-logs"),
	}
	if err := os.MkdirAll(c.logDir, 0700); err != nil {
		return nil, err
	}
	if err := os.MkdirAll(c.dir, 0700); err != nil {
		return nil, err
	}
	if opts.FetchFrequency > 0 {
		go c.recurringFetch(opts.FetchFrequency)
	}

	return &c, nil
}

func (c *gitCache) recurringFetch(freq time.Duration) {
	ticker := time.NewTicker(freq)
	for {
		if err := c.FetchAll(); err != nil {
			log.Printf("FetchAll: %v", err)
		}
		<-ticker.C
	}
}

// logfile returns a logfile open for writing with a unique name.
func (c *gitCache) logfile() (*os.File, error) {
	nm := fmt.Sprintf("%s/git.%s.log", c.logDir, time.Now().Format(time.RFC3339Nano))
	nm = strings.Replace(nm, ":", "_", -1)
	return os.Create(nm)
}

// Fetch updates the local clone of the given repository.
func (c *gitCache) Fetch(dir string) error {
	if err := c.runGit(c.dir, "--git-dir="+dir, "fetch", "origin"); err != nil {
		return err
	}

	return nil
}

// FetchAll finds all known repos and runs git-fetch on them.
func (c *gitCache) FetchAll() error {
	var dirs []string
	if err := filepath.Walk(c.dir, func(n string, fi os.FileInfo, err error) error {
		if fi.IsDir() && strings.HasSuffix(n, ".git") {
			dirs = append(dirs, n)
			return filepath.SkipDir
		}
		return nil
	}); err != nil {
		return err
	}

	for _, d := range dirs {
		if err := c.Fetch(d); err != nil {
			return fmt.Errorf("fetch %s: %v", d, err)
		}
	}

	return nil
}

// gitPath transforms a URL into a path under the gitCache directory.
func (c *gitCache) gitPath(u string) (string, error) {
	parsed, err := url.Parse(u)
	if err != nil {
		return "", err
	}

	p := path.Clean(parsed.Path)
	if path.Base(p) == ".git" {
		p = path.Dir(p)
	}
	return filepath.Join(c.dir, parsed.Host, p+".git"), nil
}

// runGit runs git with the given arguments under the given directory.
func (c *gitCache) runGit(dir string, args ...string) error {
	logfile, err := c.logfile()
	if err != nil {
		return err
	}
	defer logfile.Close()

	cmd := exec.Command("git", args...)
	cmd.Dir = dir

	var out, errOut bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &errOut
	runErr := cmd.Run()

	if _, err := fmt.Fprintf(logfile, "args: %s\ndir:%s\nEXIT: %s\n\nOUT\n%s\n\nERR\n\n", cmd.Args,
		cmd.Dir, out.String(), errOut.String()); err != nil {
		return fmt.Errorf("logfile write for %s (%v): %v",
			args, runErr, err)
	}

	if err := logfile.Close(); err != nil {
		return fmt.Errorf("logfile close for %s (%v): %v",
			args, runErr, err)
	}

	if err != nil {
		log.Printf("ran %s exit %v", cmd.Args, err)
	}
	return runErr
}

// OpenLocal returns an opened repository for the given URL, if it is available locally.
func (c *gitCache) OpenLocal(url string) *git.Repository {
	p, err := c.gitPath(url)
	if err != nil {
		return nil
	}

	repo, err := git.OpenRepository(p)
	if err != nil {
		return nil
	}
	return repo
}

// Open returns an opened repository for the given URL. If necessary,
// the repository is cloned.
func (c *gitCache) Open(url string) (*git.Repository, error) {
	// TODO(hanwen): multiple concurrent calls to Open() with the
	// same URL may race, resulting in a double clone. It's unclear
	// what will happen in that case.
	p, err := c.gitPath(url)
	if err != nil {
		return nil, err
	}

	if _, err := os.Lstat(p); os.IsNotExist(err) {
		dir, base := filepath.Split(p)
		if err := os.MkdirAll(dir, 0755); err != nil {
			return nil, err
		}
		if err := c.runGit(dir, "clone", "--bare", "--progress", "--verbose", url, base); err != nil {
			return nil, err
		}
	}
	repo, err := git.OpenRepository(p)
	return repo, err
}
