// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package project

import (
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"go.fuchsia.dev/jiri"
	"go.fuchsia.dev/jiri/gerrit"
	"go.fuchsia.dev/jiri/gitutil"
)

const (
	SourceManifestVersion = int32(0)
)

// This was created using proto file: https://github.com/luci/recipes-py/blob/master/recipe_engine/source_manifest.proto.
type SourceManifest_GitCheckout struct {
	// The canonicalized URL of the original repo that is considered the “source
	// of truth” for the source code. Ex.
	//   https://chromium.googlesource.com/chromium/tools/build.git
	//   https://github.com/luci/recipes-py
	RepoUrl string `json:"repo_url,omitempty"`

	// If different from repo_url, this can be the URL of the repo that the source
	// was actually fetched from (i.e. a mirror). Ex.
	//   https://chromium.googlesource.com/external/github.com/luci/recipes-py
	//
	// If this is empty, it's presumed to be equal to repo_url.
	FetchUrl string `json:"fetch_url,omitempty"`

	// The fully resolved revision (commit hash) of the source. Ex.
	//   3617b0eea7ec74b8e731a23fed2f4070cbc284c4
	//
	// Note that this is the raw revision bytes, not their hex-encoded form.
	Revision string `json:"revision,omitempty"`

	// The ref that the task used to resolve/fetch the revision of the source
	// (if any). Ex.
	//   refs/heads/master
	//   refs/changes/04/511804/4
	//
	// This should always be a ref on the hosted repo (not any local alias
	// like 'refs/remotes/...').
	//
	// This should always be an absolute ref (i.e. starts with 'refs/'). An
	// example of a non-absolute ref would be 'master'.
	FetchRef string `json:"fetch_ref,omitempty"`
}

type SourceManifest_Directory struct {
	GitCheckout *SourceManifest_GitCheckout `json:"git_checkout,omitempty"`
}

type SourceManifest struct {
	// Version will increment on backwards-incompatible changes only. Backwards
	// compatible changes will not alter this version number.
	//
	// Currently, the only valid version number is 0.
	Version int32 `json:"version"`

	// Map of local file system directory path (with forward slashes) to
	// a Directory message containing one or more deployments.
	//
	// The local path is relative to some job-specific root. This should be used
	// for informational/display/organization purposes, and should not be used as
	// a global primary key. i.e. if you depend on chromium/src.git being in
	// a folder called “src”, I will find you and make really angry faces at you
	// until you change it...（╬ಠ益ಠ). Instead, implementations should consider
	// indexing by e.g. git repository URL or cipd package name as more better
	// primary keys.
	Directories map[string]*SourceManifest_Directory `json:"directories"`
}

func getCLRefByCommit(jirix *jiri.X, gerritHost, revision string) (string, error) {
	hostUrl, err := url.Parse(gerritHost)
	if err != nil {
		return "", fmt.Errorf("invalid gerrit host %q: %s", gerritHost, err)
	}
	g := gerrit.New(jirix, hostUrl)
	cls, err := g.ListChangesByCommit(revision)
	if err != nil {
		return "", fmt.Errorf("not able to get CL for revision %s: %s", revision, err)
	}
	for _, c := range cls {
		if v, ok := c.Revisions[revision]; ok {
			return v.Fetch.Ref, nil
		}
	}
	return "", nil
}

func NewSourceManifest(jirix *jiri.X, projects Projects) (*SourceManifest, MultiError) {
	jirix.TimerPush("create source manifest")
	defer jirix.TimerPop()

	workQueue := make(chan Project, len(projects))
	for _, proj := range projects {
		if err := proj.relativizePaths(jirix.Root); err != nil {
			return nil, MultiError{err}
		}
		workQueue <- proj
	}
	close(workQueue)
	errs := make(chan error, len(projects))
	sm := &SourceManifest{
		Version:     SourceManifestVersion,
		Directories: make(map[string]*SourceManifest_Directory),
	}
	var mux sync.Mutex
	processProject := func(proj Project) error {
		gc := &SourceManifest_GitCheckout{
			RepoUrl: rewriteRemote(jirix, proj.Remote),
		}
		scm := gitutil.New(jirix, gitutil.RootDirOpt(filepath.Join(jirix.Root, proj.Path)))
		if rev, err := scm.CurrentRevision(); err != nil {
			return err
		} else {
			gc.Revision = rev
		}
		if proj.RemoteBranch == "" {
			proj.RemoteBranch = "master"
		}
		branchMap, err := scm.ListRemoteBranchesContainingRef(gc.Revision)
		if err != nil {
			return err
		}
		if branchMap["origin/"+proj.RemoteBranch] {
			gc.FetchRef = "refs/heads/" + proj.RemoteBranch
		} else {
			for b := range branchMap {
				if strings.HasPrefix(b, "origin/HEAD ") {
					continue
				}
				if strings.HasPrefix(b, "origin") {
					gc.FetchRef = "refs/heads/" + strings.TrimLeft(b, "origin/")
					break
				}
			}

			// Try getting from gerrit
			if gc.FetchRef == "" && proj.GerritHost != "" {
				if ref, err := getCLRefByCommit(jirix, proj.GerritHost, gc.Revision); err != nil {
					// Don't fail
					jirix.Logger.Debugf("Error while fetching from gerrit for project %q: %s", proj.Name, err)
				} else if ref == "" {
					jirix.Logger.Debugf("Cannot get ref for project: %q, revision: %q", proj.Name, gc.Revision)
				} else {
					gc.FetchRef = ref
				}
			}
		}
		mux.Lock()
		sm.Directories[proj.Path] = &SourceManifest_Directory{GitCheckout: gc}
		mux.Unlock()
		return nil
	}

	var wg sync.WaitGroup
	for i := uint(0); i < jirix.Jobs; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for p := range workQueue {
				if err := processProject(p); err != nil {
					errs <- err
				}
			}
		}()
	}
	wg.Wait()
	close(errs)
	var multiErr MultiError
	for err := range errs {
		multiErr = append(multiErr, err)
	}
	return sm, multiErr
}

func (sm *SourceManifest) ToFile(jirix *jiri.X, filename string) error {
	if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
		return fmtError(err)
	}
	out, err := json.MarshalIndent(sm, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to serialize JSON output: %s\n", err)
	}

	err = os.WriteFile(filename, out, 0600)
	if err != nil {
		return fmt.Errorf("failed write JSON output to %s: %s\n", filename, err)
	}

	return nil
}
