package ddb

import (
	"context"
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"net"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

func DynamoDbTest(ctx context.Context) {
	tilog.Info(ctx, "dynamoDbTest init")
	client := getDynamodbClientDev(ctx)
	listTables(ctx, client)
	//createTables(ctx, client)

}

func getDynamodbClient(ctx context.Context) *dynamodb.DynamoDB {
	//region := "us-west-2"
	region := os.Getenv("AWS_REGION")

	tilog.Info(ctx, "DynamodbClient init", zap.Any("region", region))
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			Region: &region,
		},
		SharedConfigState: session.SharedConfigStateFromEnv,
	}))

	// Create DynamoDB client
	client := dynamodb.New(sess)
	return client
}

func getDynamodbClientDev(ctx context.Context) *dynamodb.DynamoDB {

	region := os.Getenv("AWS_REGION")
	roleArn := os.Getenv("AWS_ROLE_ARN")
	tilog.Info(ctx, "aws info ", zap.Any("region", region), zap.Any("awsRoleArn", roleArn), zap.Any("ip", getIPs()))

	tilog.Info(ctx, "DynamodbClient init ")

	sess := session.Must(session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			Region: &region,
		},
		SharedConfigState: session.SharedConfigStateFromEnv,
	}))

	// dev/staging account role
	crossAccountRoleArn := "arn:aws:iam::385595570414:role/dev-staging-data-api-dynamodb-role"
	creds := stscreds.NewCredentials(sess, crossAccountRoleArn, func(arp *stscreds.AssumeRoleProvider) {
		arp.RoleSessionName = "dev-role-session-name"
		arp.Duration = 60 * time.Minute
		arp.ExpiryWindow = 30 * time.Second
	})

	client := dynamodb.New(sess, aws.NewConfig().WithCredentials(creds))

	return client
}

func listTables(ctx context.Context, client *dynamodb.DynamoDB) {
	tilog.Info(ctx, "--------list tables--------")

	var limit int64 = 10
	resp2, err := client.ListTables(&dynamodb.ListTablesInput{
		Limit: &limit,
	})
	if err != nil {
		fmt.Printf("failed to list tables, %v\n", err)
		tilog.Info(ctx, "failed to list tables,", zap.Error(err))
	}

	for _, tableName := range resp2.TableNames {
		tilog.Info(ctx, "list tables,", zap.Any("table name", tableName))
	}
}

func createTables(ctx context.Context, client *dynamodb.DynamoDB) {

	attributeDefinitions := []*dynamodb.AttributeDefinition{
		{
			AttributeName: aws.String("Year"),
			AttributeType: aws.String("N"),
		},
		{
			AttributeName: aws.String("Title"),
			AttributeType: aws.String("S"),
		},
	}

	keySchema := []*dynamodb.KeySchemaElement{
		{
			AttributeName: aws.String("Year"),
			KeyType:       aws.String("HASH"),
		},
		{
			AttributeName: aws.String("Title"),
			KeyType:       aws.String("RANGE"),
		},
	}

	provisionedThroughput := &dynamodb.ProvisionedThroughput{
		ReadCapacityUnits:  aws.Int64(10),
		WriteCapacityUnits: aws.Int64(10),
	}
	// snippet-end:[dynamodb.go.create_new_table.create_input]
	timeStr := time.Now().Format("2006-01-02_15_04_05")
	//timeStr := time.Now().Format("2006-01-02_15_04_05")
	tableName := "wangletian-test-" + timeStr
	err := MakeTable(client, attributeDefinitions, keySchema, provisionedThroughput, &tableName)
	if err != nil {
		tilog.Info(ctx, "Created the table fail", zap.Error(err))
		return
	}
	tilog.Info(ctx, "Created the table", zap.Any("tableName", tableName))

}

// MakeTable creates an Amazon DynamoDB table
// Inputs:
//     sess is the current session, which provides configuration for the SDK's service clients
//     attributeDefinitions describe the table's attributes
//     keySchema defines the table schema
//     provisionedThroughput defines the throughput
//     tableName is the name of the table
// Output:
//     If success, nil
//     Otherwise, an error from the call to CreateTable
func MakeTable(svc dynamodbiface.DynamoDBAPI, attributeDefinitions []*dynamodb.AttributeDefinition, keySchema []*dynamodb.KeySchemaElement, provisionedThroughput *dynamodb.ProvisionedThroughput, tableName *string) error {
	// snippet-start:[dynamodb.go.create_new_table.call]

	_, err := svc.CreateTable(&dynamodb.CreateTableInput{
		AttributeDefinitions:  attributeDefinitions,
		KeySchema:             keySchema,
		ProvisionedThroughput: provisionedThroughput,
		TableName:             tableName,
	})
	// snippet-end:[dynamodb.go.create_new_table.call]
	return err
}

func getIPs() (ips []string) {

	interfaceAddr, err := net.InterfaceAddrs()
	if err != nil {
		fmt.Printf("fail to get net interface addrs: %v", err)
		return ips
	}

	for _, address := range interfaceAddr {
		ipNet, isValidIpNet := address.(*net.IPNet)
		if isValidIpNet && !ipNet.IP.IsLoopback() {
			if ipNet.IP.To4() != nil {
				ips = append(ips, ipNet.IP.String())
			}
		}
	}
	return ips
}
