// +build ignore

package main

import (
	"bytes"
	"go/format"
	"log"
	"os"
	"sort"
	"strings"
	"text/template"

	"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

const filename = `create_tags_gen.go`

var serviceNames = []string{
	"ec2",
}

type TemplateData struct {
	ServiceNames []string
}

func main() {
	// Always sort to reduce any potential generation churn
	sort.Strings(serviceNames)

	templateData := TemplateData{
		ServiceNames: serviceNames,
	}
	templateFuncMap := template.FuncMap{
		"ClientType":                        keyvaluetags.ServiceClientType,
		"ResourceNotFoundErrorCode":         keyvaluetags.ServiceResourceNotFoundErrorCode,
		"ResourceNotFoundErrorCodeContains": keyvaluetags.ServiceResourceNotFoundErrorCodeContains,
		"RetryCreationOnResourceNotFound":   keyvaluetags.ServiceRetryCreationOnResourceNotFound,
		"TagFunction":                       keyvaluetags.ServiceTagFunction,
		"TagFunctionBatchSize":              keyvaluetags.ServiceTagFunctionBatchSize,
		"TagInputCustomValue":               keyvaluetags.ServiceTagInputCustomValue,
		"TagInputIdentifierField":           keyvaluetags.ServiceTagInputIdentifierField,
		"TagInputIdentifierRequiresSlice":   keyvaluetags.ServiceTagInputIdentifierRequiresSlice,
		"TagInputTagsField":                 keyvaluetags.ServiceTagInputTagsField,
		"TagPackage":                        keyvaluetags.ServiceTagPackage,
		"TagResourceTypeField":              keyvaluetags.ServiceTagResourceTypeField,
		"TagTypeIdentifierField":            keyvaluetags.ServiceTagTypeIdentifierField,
		"Title":                             strings.Title,
	}

	tmpl, err := template.New("createtags").Funcs(templateFuncMap).Parse(templateBody)

	if err != nil {
		log.Fatalf("error parsing template: %s", err)
	}

	var buffer bytes.Buffer
	err = tmpl.Execute(&buffer, templateData)

	if err != nil {
		log.Fatalf("error executing template: %s", err)
	}

	generatedFileContents, err := format.Source(buffer.Bytes())

	if err != nil {
		log.Fatalf("error formatting generated file: %s", err)
	}

	f, err := os.Create(filename)

	if err != nil {
		log.Fatalf("error creating file (%s): %s", filename, err)
	}

	defer f.Close()

	_, err = f.Write(generatedFileContents)

	if err != nil {
		log.Fatalf("error writing to file (%s): %s", filename, err)
	}
}

var templateBody = `
// Code generated by generators/createtags/main.go; DO NOT EDIT.

package keyvaluetags

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
{{- range .ServiceNames }}
	"github.com/aws/aws-sdk-go/service/{{ . }}"
{{- end }}
	"github.com/hashicorp/aws-sdk-go-base/tfawserr"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

const EventualConsistencyTimeout = 5 * time.Minute

{{- range .ServiceNames }}

// {{ . | Title }}CreateTags creates {{ . }} service tags for new resources.
// The identifier is typically the Amazon Resource Name (ARN), although
// it may also be a different identifier depending on the service.
func {{ . | Title }}CreateTags(conn {{ . | ClientType }}, identifier string{{ if . | TagResourceTypeField }}, resourceType string{{ end }}, tagsMap interface{}) error {
	tags := New(tagsMap)

	{{- if . | TagFunctionBatchSize }}
	for _, tags := range tags.Chunks({{ . | TagFunctionBatchSize }}) {
	{{- end }}
	input := &{{ . | TagPackage }}.{{ . | TagFunction }}Input{
		{{- if not ( . | TagTypeIdentifierField ) }}
		{{- if . | TagInputIdentifierRequiresSlice }}
		{{ . | TagInputIdentifierField }}: aws.StringSlice([]string{identifier}),
		{{- else }}
		{{ . | TagInputIdentifierField }}: aws.String(identifier),
		{{- end }}
		{{- if . | TagResourceTypeField }}
		{{ . | TagResourceTypeField }}:    aws.String(resourceType),
		{{- end }}
		{{- end }}
		{{- if . | TagInputCustomValue }}
		{{ . | TagInputTagsField }}:       {{ . | TagInputCustomValue }},
		{{- else }}
		{{ . | TagInputTagsField }}:       tags.IgnoreAws().{{ . | Title }}Tags(),
		{{- end }}
	}

	{{- if . | RetryCreationOnResourceNotFound }}

	err := resource.Retry(EventualConsistencyTimeout, func() *resource.RetryError {
		_, err := conn.{{ . | TagFunction }}(input)

		{{- if . | ResourceNotFoundErrorCodeContains }}

		if tfawserr.ErrCodeContains(err, "{{ . | ResourceNotFoundErrorCodeContains }}") {

		{{- else }}

		if tfawserr.ErrCodeEquals(err, {{ . | ResourceNotFoundErrorCode }}) {

		{{- end }}
			return resource.RetryableError(err)
		}

		if err != nil {
			return resource.NonRetryableError(err)
		}

		return nil
	})

	if tfresource.TimedOut(err) {
		_, err = conn.{{ . | TagFunction }}(input)
	}
	{{- else }}
	_, err := conn.{{ . | TagFunction }}(input)
	{{- end }}

	if err != nil {
		return fmt.Errorf("error tagging resource (%s): %w", identifier, err)
	}
	{{- if . | TagFunctionBatchSize }}
	}
	{{- end }}

	return nil
}
{{- end }}
`
