package ado

import (
	"context"
	"fmt"

	"github.com/microsoft/azure-devops-go-api/azuredevops"
	"github.com/microsoft/azure-devops-go-api/azuredevops/build"
	"github.com/pkg/errors"
)

const azureUrl = "https://dev.azure.com"

type BuildClient interface {
	UpdateVariables(variables []Variable) error
}

type BuildClientImpl struct {
	ctx         context.Context
	buildClient build.Client
	project     string
	pipelineID  int
}

type Variable struct {
	Name          string
	Value         string
	IsSecret      bool
	AllowOverride bool
}

//UpdateVariables updates variables in build definition or creates them if they are missing
func (bc *BuildClientImpl) UpdateVariables(variables []Variable) error {
	if len(variables) == 0 {
		return errors.New("error: slice variables must not be empty")
	}
	getDefinitionArgs := build.GetDefinitionArgs{
		Project:      &bc.project,
		DefinitionId: &bc.pipelineID,
	}

	// Get a build definition
	buildDefinition, err := bc.buildClient.GetDefinition(bc.ctx, getDefinitionArgs)
	if err != nil {
		return errors.Wrapf(err, "error: get definition failed")
	}

	buildDefinitionVars := map[string]build.BuildDefinitionVariable{}
	if buildDefinition.Variables != nil {
		buildDefinitionVars = *buildDefinition.Variables
	}

	for _, variable := range variables {
		buildDefinitionVars[variable.Name] = build.BuildDefinitionVariable{
			Value:         &variable.Value,
			IsSecret:      &variable.IsSecret,
			AllowOverride: &variable.AllowOverride,
		}
	}

	buildDefinition.Variables = &buildDefinitionVars

	updateDefinitionArgs := build.UpdateDefinitionArgs{
		Definition:   buildDefinition,
		Project:      &bc.project,
		DefinitionId: &bc.pipelineID,
	}

	_, err = bc.buildClient.UpdateDefinition(bc.ctx, updateDefinitionArgs)
	if err != nil {
		return errors.Wrapf(err, "error: update definition failed")
	}

	return nil
}

//NewBuildClient Create a client to interact with the Build area
func NewBuildClient(organization string, personalAccessToken string, project string, pipelineID int) (BuildClient, error) {
	if organization == "" {
		return nil, errors.New("error: organization must not be empty")
	}
	if personalAccessToken == "" {
		return nil, errors.New("error: personal access token must not be empty")
	}
	if project == "" {
		return nil, errors.New("error: project must not be empty")
	}

	organizationUrl := fmt.Sprintf("%s/%s", azureUrl, organization)
	// Create a connection to your organization
	connection := azuredevops.NewPatConnection(organizationUrl, personalAccessToken)

	ctx := context.Background()

	// Create a client to interact with the Core area
	buildClient, err := build.NewClient(ctx, connection)
	if err != nil {
		return nil, err
	}

	buildClientImpl := &BuildClientImpl{
		ctx:         ctx,
		buildClient: buildClient,
		project:     project,
		pipelineID:  pipelineID,
	}

	return buildClientImpl, nil
}
