package flow

import (
	"errors"
	"fmt"

	"go.starlark.net/starlark"
)

const (
	localSource   = "localSource"
	sourceBuiltin = "source"
)

// TODO validate parameters
func sourceBuiltinFunc(thread *starlark.Thread, fn *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
	if len(args) > 0 {
		return nil, fmt.Errorf("%s: unexpected positional arguments", fn.Name())
	}
	var (
		name        string
		projectPath string
		branch      string
		tag         string
		commit      string
	)
	err := starlark.UnpackArgs(fn.Name(), nil, kwargs,
		"name", &name,
		"project_path", &projectPath,
		"branch??", &branch,
		"tag??", &tag,
		"commit??", &commit,
	)
	if err != nil {
		return nil, err
	}
	fullGitRef, err := resolveToFullRef(branch, tag, commit)
	if err != nil {
		return nil, err
	}
	s, ok := thread.Local(localSource).(Source)
	if !ok {
		return nil, errors.New("internal error: local source not found")
	}
	err = s.RecordSource(thread, name, projectPath, fullGitRef)
	if err != nil {
		return nil, err
	}

	return starlark.None, nil
}

func resolveToFullRef(branch, tag, commit string) (string, error) {
	switch {
	case branch == "" && tag == "" && commit == "":
		return "", nil
	case branch != "":
		return "refs/heads/" + branch, nil
	case tag != "":
		return "refs/tags/" + tag, nil
	case commit != "": // TODO validate commit sha
		return commit, nil
	default:
		return "", errors.New("none or only one of branch, tag or commit can be specified")
	}
}
