// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.

// +build !oss

package config

import (
	"bytes"
	"context"
	"strings"

	"github.com/drone/drone/core"

	"github.com/google/go-jsonnet"
)

// Jsonnet returns a configuration service that fetches the
// jsonnet file directly from the source code management (scm)
// system and converts to a yaml file.
func Jsonnet(service core.FileService, enabled bool) core.ConfigService {
	return &jsonnetPlugin{
		enabled: enabled,
		repos:   &repo{files: service},
	}
}

type jsonnetPlugin struct {
	enabled bool
	repos   *repo
}

func (p *jsonnetPlugin) Find(ctx context.Context, req *core.ConfigArgs) (*core.Config, error) {
	if p.enabled == false {
		return nil, nil
	}

	// if the file extension is not jsonnet we can
	// skip this plugin by returning zero values.
	if strings.HasSuffix(req.Repo.Config, ".jsonnet") == false {
		return nil, nil
	}

	// get the file contents.
	config, err := p.repos.Find(ctx, req)
	if err != nil {
		return nil, err
	}

	// TODO(bradrydzewski) temporarily disable file imports
	// TODO(bradrydzewski) handle object vs array output

	// create the jsonnet vm
	vm := jsonnet.MakeVM()
	vm.MaxStack = 500
	vm.StringOutput = false
	vm.ErrorFormatter.SetMaxStackTraceSize(20)

	// convert the jsonnet file to yaml
	buf := new(bytes.Buffer)
	docs, err := vm.EvaluateSnippetStream(req.Repo.Config, config.Data)
	if err != nil {
		return nil, err
	}

	// the jsonnet vm returns a stream of yaml documents
	// that need to be combined into a single yaml file.
	for _, doc := range docs {
		buf.WriteString("---")
		buf.WriteString("\n")
		buf.WriteString(doc)
	}

	config.Data = buf.String()
	return config, nil
}
