// +build codegen

package api

import (
	"fmt"
	"path/filepath"
	"strings"
)

// customizationPasses Executes customization logic for the API by package name.
func (a *API) customizationPasses() {
	var svcCustomizations = map[string]func(*API){
		"s3":              s3Customizations,
		"cloudfront":      cloudfrontCustomizations,
		"dynamodbstreams": dynamodbstreamsCustomizations,
	}

	if fn := svcCustomizations[a.PackageName()]; fn != nil {
		fn(a)
	}

	blobDocStringCustomizations(a)
}

const base64MarshalDocStr = "// %s is automatically base64 encoded/decoded by the SDK.\n"

func blobDocStringCustomizations(a *API) {
	for _, s := range a.Shapes {
		payloadMemberName := s.Payload

		for refName, ref := range s.MemberRefs {
			if refName == payloadMemberName {
				// Payload members have their own encoding and may
				// be raw bytes or io.Reader
				continue
			}
			if ref.Shape.Type == "blob" {
				docStr := fmt.Sprintf(base64MarshalDocStr, refName)
				if len(strings.TrimSpace(ref.Shape.Documentation)) != 0 {
					ref.Shape.Documentation += "//\n" + docStr
				} else if len(strings.TrimSpace(ref.Documentation)) != 0 {
					ref.Documentation += "//\n" + docStr
				} else {
					ref.Documentation = docStr
				}
			}
		}
	}
}

// s3Customizations customizes the API generation to replace values specific to S3.
func s3Customizations(a *API) {
	var strExpires *Shape

	for name, s := range a.Shapes {
		// Remove ContentMD5 members
		if _, ok := s.MemberRefs["ContentMD5"]; ok {
			delete(s.MemberRefs, "ContentMD5")
		}

		// Expires should be a string not time.Time since the format is not
		// enforced by S3, and any value can be set to this field outside of the SDK.
		if strings.HasSuffix(name, "Output") {
			if ref, ok := s.MemberRefs["Expires"]; ok {
				if strExpires == nil {
					newShape := *ref.Shape
					strExpires = &newShape
					strExpires.Type = "string"
					strExpires.refs = []*ShapeRef{}
				}
				ref.Shape.removeRef(ref)
				ref.Shape = strExpires
				ref.Shape.refs = append(ref.Shape.refs, &s.MemberRef)
			}
		}
	}
}

// cloudfrontCustomizations customized the API generation to replace values
// specific to CloudFront.
func cloudfrontCustomizations(a *API) {
	// MaxItems members should always be integers
	for _, s := range a.Shapes {
		if ref, ok := s.MemberRefs["MaxItems"]; ok {
			ref.ShapeName = "Integer"
			ref.Shape = a.Shapes["Integer"]
		}
	}
}

// dynamodbstreamsCustomizations references any duplicate shapes from DynamoDB
func dynamodbstreamsCustomizations(a *API) {
	p := strings.Replace(a.path, "streams.dynamodb", "dynamodb", -1)
	file := filepath.Join(p, "api-2.json")

	dbAPI := API{}
	dbAPI.Attach(file)
	dbAPI.Setup()

	for n := range a.Shapes {
		if _, ok := dbAPI.Shapes[n]; ok {
			a.Shapes[n].resolvePkg = "github.com/aws/aws-sdk-go/service/dynamodb"
		}
	}
}
