// Code generated by smithy-go-codegen DO NOT EDIT.

package ec2

import (
	"context"
	"fmt"
	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
	"github.com/aws/aws-sdk-go-v2/service/ec2/types"
	presignedurlcust "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url"
	"github.com/aws/smithy-go/middleware"
	smithyhttp "github.com/aws/smithy-go/transport/http"
)

// Creates an exact copy of an Amazon EBS snapshot.
//
// The location of the source snapshot determines whether you can copy it or not,
// and the allowed destinations for the snapshot copy.
//
//   - If the source snapshot is in a Region, you can copy it within that Region,
//     to another Region, to an Outpost associated with that Region, or to a Local Zone
//     in that Region.
//
//   - If the source snapshot is in a Local Zone, you can copy it within that
//     Local Zone, to another Local Zone in the same zone group, or to the parent
//     Region of the Local Zone.
//
//   - If the source snapshot is on an Outpost, you can't copy it.
//
// When copying snapshots to a Region, copies of encrypted EBS snapshots remain
// encrypted. Copies of unencrypted snapshots remain unencrypted, unless you enable
// encryption for the snapshot copy operation. By default, encrypted snapshot
// copies use the default KMS key; however, you can specify a different KMS key. To
// copy an encrypted snapshot that has been shared from another account, you must
// have permissions for the KMS key used to encrypt the snapshot.
//
// Snapshots copied to an Outpost are encrypted by default using the default
// encryption key for the Region, or a different key that you specify in the
// request using KmsKeyId. Outposts do not support unencrypted snapshots. For more
// information, see [Amazon EBS local snapshots on Outposts]in the Amazon EBS User Guide.
//
// Snapshots copies have an arbitrary source volume ID. Do not use this volume ID
// for any purpose.
//
// For more information, see [Copy an Amazon EBS snapshot] in the Amazon EBS User Guide.
//
// [Copy an Amazon EBS snapshot]: https://docs.aws.amazon.com/ebs/latest/userguide/ebs-copy-snapshot.html
// [Amazon EBS local snapshots on Outposts]: https://docs.aws.amazon.com/ebs/latest/userguide/snapshots-outposts.html#ami
func (c *Client) CopySnapshot(ctx context.Context, params *CopySnapshotInput, optFns ...func(*Options)) (*CopySnapshotOutput, error) {
	if params == nil {
		params = &CopySnapshotInput{}
	}

	result, metadata, err := c.invokeOperation(ctx, "CopySnapshot", params, optFns, c.addOperationCopySnapshotMiddlewares)
	if err != nil {
		return nil, err
	}

	out := result.(*CopySnapshotOutput)
	out.ResultMetadata = metadata
	return out, nil
}

type CopySnapshotInput struct {

	// The ID of the Region that contains the snapshot to be copied.
	//
	// This member is required.
	SourceRegion *string

	// The ID of the EBS snapshot to copy.
	//
	// This member is required.
	SourceSnapshotId *string

	// Not supported when copying snapshots to or from Local Zones or Outposts.
	//
	// Specify a completion duration, in 15 minute increments, to initiate a
	// time-based snapshot copy. Time-based snapshot copy operations complete within
	// the specified duration. For more information, see [Time-based copies].
	//
	// If you do not specify a value, the snapshot copy operation is completed on a
	// best-effort basis.
	//
	// [Time-based copies]: https://docs.aws.amazon.com/ebs/latest/userguide/time-based-copies.html
	CompletionDurationMinutes *int32

	// A description for the EBS snapshot.
	Description *string

	// The Local Zone, for example, cn-north-1-pkx-1a to which to copy the snapshot.
	//
	// Only supported when copying a snapshot to a Local Zone.
	DestinationAvailabilityZone *string

	// The Amazon Resource Name (ARN) of the Outpost to which to copy the snapshot.
	//
	// Only supported when copying a snapshot to an Outpost.
	//
	// For more information, see [Copy snapshots from an Amazon Web Services Region to an Outpost] in the Amazon EBS User Guide.
	//
	// [Copy snapshots from an Amazon Web Services Region to an Outpost]: https://docs.aws.amazon.com/ebs/latest/userguide/snapshots-outposts.html#copy-snapshots
	DestinationOutpostArn *string

	// Checks whether you have the required permissions for the action, without
	// actually making the request, and provides an error response. If you have the
	// required permissions, the error response is DryRunOperation . Otherwise, it is
	// UnauthorizedOperation .
	DryRun *bool

	// To encrypt a copy of an unencrypted snapshot if encryption by default is not
	// enabled, enable encryption using this parameter. Otherwise, omit this parameter.
	// Encrypted snapshots are encrypted, even if you omit this parameter and
	// encryption by default is not enabled. You cannot set this parameter to false.
	// For more information, see [Amazon EBS encryption]in the Amazon EBS User Guide.
	//
	// [Amazon EBS encryption]: https://docs.aws.amazon.com/ebs/latest/userguide/ebs-encryption.html
	Encrypted *bool

	// The identifier of the KMS key to use for Amazon EBS encryption. If this
	// parameter is not specified, your KMS key for Amazon EBS is used. If KmsKeyId is
	// specified, the encrypted state must be true .
	//
	// You can specify the KMS key using any of the following:
	//
	//   - Key ID. For example, 1234abcd-12ab-34cd-56ef-1234567890ab.
	//
	//   - Key alias. For example, alias/ExampleAlias.
	//
	//   - Key ARN. For example,
	//   arn:aws:kms:us-east-1:012345678910:key/1234abcd-12ab-34cd-56ef-1234567890ab.
	//
	//   - Alias ARN. For example,
	//   arn:aws:kms:us-east-1:012345678910:alias/ExampleAlias.
	//
	// Amazon Web Services authenticates the KMS key asynchronously. Therefore, if you
	// specify an ID, alias, or ARN that is not valid, the action can appear to
	// complete, but eventually fails.
	KmsKeyId *string

	// When you copy an encrypted source snapshot using the Amazon EC2 Query API, you
	// must supply a pre-signed URL. This parameter is optional for unencrypted
	// snapshots. For more information, see [Query requests].
	//
	// The PresignedUrl should use the snapshot source endpoint, the CopySnapshot
	// action, and include the SourceRegion , SourceSnapshotId , and DestinationRegion
	// parameters. The PresignedUrl must be signed using Amazon Web Services Signature
	// Version 4. Because EBS snapshots are stored in Amazon S3, the signing algorithm
	// for this parameter uses the same logic that is described in [Authenticating Requests: Using Query Parameters (Amazon Web Services Signature Version 4)]in the Amazon S3
	// API Reference. An invalid or improperly signed PresignedUrl will cause the copy
	// operation to fail asynchronously, and the snapshot will move to an error state.
	//
	// [Authenticating Requests: Using Query Parameters (Amazon Web Services Signature Version 4)]: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
	// [Query requests]: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Query-Requests.html
	PresignedUrl *string

	// The tags to apply to the new snapshot.
	TagSpecifications []types.TagSpecification

	// Used by the SDK's PresignURL autofill customization to specify the region the
	// of the client's request.
	destinationRegion *string

	noSmithyDocumentSerde
}

type CopySnapshotOutput struct {

	// The ID of the new snapshot.
	SnapshotId *string

	// Any tags applied to the new snapshot.
	Tags []types.Tag

	// Metadata pertaining to the operation's result.
	ResultMetadata middleware.Metadata

	noSmithyDocumentSerde
}

func (c *Client) addOperationCopySnapshotMiddlewares(stack *middleware.Stack, options Options) (err error) {
	if err := stack.Serialize.Add(&setOperationInputMiddleware{}, middleware.After); err != nil {
		return err
	}
	err = stack.Serialize.Add(&awsEc2query_serializeOpCopySnapshot{}, middleware.After)
	if err != nil {
		return err
	}
	err = stack.Deserialize.Add(&awsEc2query_deserializeOpCopySnapshot{}, middleware.After)
	if err != nil {
		return err
	}
	if err := addProtocolFinalizerMiddlewares(stack, options, "CopySnapshot"); err != nil {
		return fmt.Errorf("add protocol finalizers: %v", err)
	}

	if err = addlegacyEndpointContextSetter(stack, options); err != nil {
		return err
	}
	if err = addSetLoggerMiddleware(stack, options); err != nil {
		return err
	}
	if err = addClientRequestID(stack); err != nil {
		return err
	}
	if err = addComputeContentLength(stack); err != nil {
		return err
	}
	if err = addResolveEndpointMiddleware(stack, options); err != nil {
		return err
	}
	if err = addComputePayloadSHA256(stack); err != nil {
		return err
	}
	if err = addRetry(stack, options); err != nil {
		return err
	}
	if err = addRawResponseToMetadata(stack); err != nil {
		return err
	}
	if err = addRecordResponseTiming(stack); err != nil {
		return err
	}
	if err = addSpanRetryLoop(stack, options); err != nil {
		return err
	}
	if err = addClientUserAgent(stack, options); err != nil {
		return err
	}
	if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = addCopySnapshotPresignURLMiddleware(stack, options); err != nil {
		return err
	}
	if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil {
		return err
	}
	if err = addTimeOffsetBuild(stack, c); err != nil {
		return err
	}
	if err = addUserAgentRetryMode(stack, options); err != nil {
		return err
	}
	if err = addCredentialSource(stack, options); err != nil {
		return err
	}
	if err = addOpCopySnapshotValidationMiddleware(stack); err != nil {
		return err
	}
	if err = stack.Initialize.Add(newServiceMetadataMiddleware_opCopySnapshot(options.Region), middleware.Before); err != nil {
		return err
	}
	if err = addRecursionDetection(stack); err != nil {
		return err
	}
	if err = addRequestIDRetrieverMiddleware(stack); err != nil {
		return err
	}
	if err = addResponseErrorMiddleware(stack); err != nil {
		return err
	}
	if err = addRequestResponseLogging(stack, options); err != nil {
		return err
	}
	if err = addDisableHTTPSMiddleware(stack, options); err != nil {
		return err
	}
	if err = addInterceptBeforeRetryLoop(stack, options); err != nil {
		return err
	}
	if err = addInterceptAttempt(stack, options); err != nil {
		return err
	}
	if err = addInterceptExecution(stack, options); err != nil {
		return err
	}
	if err = addInterceptBeforeSerialization(stack, options); err != nil {
		return err
	}
	if err = addInterceptAfterSerialization(stack, options); err != nil {
		return err
	}
	if err = addInterceptBeforeSigning(stack, options); err != nil {
		return err
	}
	if err = addInterceptAfterSigning(stack, options); err != nil {
		return err
	}
	if err = addInterceptTransmit(stack, options); err != nil {
		return err
	}
	if err = addInterceptBeforeDeserialization(stack, options); err != nil {
		return err
	}
	if err = addInterceptAfterDeserialization(stack, options); err != nil {
		return err
	}
	if err = addSpanInitializeStart(stack); err != nil {
		return err
	}
	if err = addSpanInitializeEnd(stack); err != nil {
		return err
	}
	if err = addSpanBuildRequestStart(stack); err != nil {
		return err
	}
	if err = addSpanBuildRequestEnd(stack); err != nil {
		return err
	}
	return nil
}

func copyCopySnapshotInputForPresign(params interface{}) (interface{}, error) {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return nil, fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	cpy := *input
	return &cpy, nil
}
func getCopySnapshotPresignedUrl(params interface{}) (string, bool, error) {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return ``, false, fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	if input.PresignedUrl == nil || len(*input.PresignedUrl) == 0 {
		return ``, false, nil
	}
	return *input.PresignedUrl, true, nil
}
func getCopySnapshotSourceRegion(params interface{}) (string, bool, error) {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return ``, false, fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	if input.SourceRegion == nil || len(*input.SourceRegion) == 0 {
		return ``, false, nil
	}
	return *input.SourceRegion, true, nil
}
func setCopySnapshotPresignedUrl(params interface{}, value string) error {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	input.PresignedUrl = &value
	return nil
}
func setCopySnapshotdestinationRegion(params interface{}, value string) error {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	input.destinationRegion = &value
	return nil
}
func addCopySnapshotPresignURLMiddleware(stack *middleware.Stack, options Options) error {
	return presignedurlcust.AddMiddleware(stack, presignedurlcust.Options{
		Accessor: presignedurlcust.ParameterAccessor{
			GetPresignedURL: getCopySnapshotPresignedUrl,

			GetSourceRegion: getCopySnapshotSourceRegion,

			CopyInput: copyCopySnapshotInputForPresign,

			SetDestinationRegion: setCopySnapshotdestinationRegion,

			SetPresignedURL: setCopySnapshotPresignedUrl,
		},
		Presigner: &presignAutoFillCopySnapshotClient{client: NewPresignClient(New(options))},
	})
}

type presignAutoFillCopySnapshotClient struct {
	client *PresignClient
}

// PresignURL is a middleware accessor that satisfies URLPresigner interface.
func (c *presignAutoFillCopySnapshotClient) PresignURL(ctx context.Context, srcRegion string, params interface{}) (*v4.PresignedHTTPRequest, error) {
	input, ok := params.(*CopySnapshotInput)
	if !ok {
		return nil, fmt.Errorf("expect *CopySnapshotInput type, got %T", params)
	}
	optFn := func(o *Options) {
		o.Region = srcRegion
		o.APIOptions = append(o.APIOptions, presignedurlcust.RemoveMiddleware)
	}
	presignOptFn := WithPresignClientFromClientOptions(optFn)
	return c.client.PresignCopySnapshot(ctx, input, presignOptFn)
}

func newServiceMetadataMiddleware_opCopySnapshot(region string) *awsmiddleware.RegisterServiceMetadata {
	return &awsmiddleware.RegisterServiceMetadata{
		Region:        region,
		ServiceID:     ServiceID,
		OperationName: "CopySnapshot",
	}
}

// PresignCopySnapshot is used to generate a presigned HTTP Request which contains
// presigned URL, signed headers and HTTP method used.
func (c *PresignClient) PresignCopySnapshot(ctx context.Context, params *CopySnapshotInput, optFns ...func(*PresignOptions)) (*v4.PresignedHTTPRequest, error) {
	if params == nil {
		params = &CopySnapshotInput{}
	}
	options := c.options.copy()
	for _, fn := range optFns {
		fn(&options)
	}
	clientOptFns := append(options.ClientOptions, withNopHTTPClientAPIOption)

	result, _, err := c.client.invokeOperation(ctx, "CopySnapshot", params, clientOptFns,
		c.client.addOperationCopySnapshotMiddlewares,
		presignConverter(options).convertToPresignMiddleware,
	)
	if err != nil {
		return nil, err
	}

	out := result.(*v4.PresignedHTTPRequest)
	return out, nil
}
