package service

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/organizations"
	"github.com/spf13/viper"
	"google.golang.org/api/option"
	"google.golang.org/api/storage/v1"

	"github.com/pingcap-inc/data-ingestion-tools/internal/itcronjob/store"
	"github.com/pingcap-inc/data-ingestion-tools/pkg/log"
)

type AwsSrv interface {
	FetchAccounts(ctx aws.Context) error
}

type awsService struct {
	store store.Factory
}

var _ AwsSrv = (*awsService)(nil)

func newAws(str *service) *awsService {
	return &awsService{store: str.store}
}

type AWSToken struct {
	AccessKeyId     string    `json:"accessKeyId"`
	SecretAccessKey string    `json:"secretAccessKey"`
	SessionToken    string    `json:"sessionToken"`
	Expiration      time.Time `json:"expiration"`
}
type AWSAccount struct {
	AccountID string `json:"accountId"`
	Name      string `json:"name"`
}

func (a *awsService) FetchAccounts(ctx context.Context) error {
	storageSrv, err := storage.NewService(context.Background(), option.WithCredentialsFile(viper.GetString("gcs.sa")))
	if err != nil {
		log.L(ctx).Errorf("storage.NewService error: %v", err)

		return err
	}
	download, err := storageSrv.Objects.Get("aws_data_cloud", "aws-token.json").Download()
	if err != nil {
		log.L(ctx).Errorf("storageSrv.Objects.Get error: %v", err)

		return err
	}
	defer download.Body.Close()
	body, err := io.ReadAll(download.Body)
	if err != nil {
		log.L(ctx).Errorf("io.ReadAll error: %v", err)

		return err
	}
	var token AWSToken
	err = json.Unmarshal(body, &token)
	if err != nil {
		log.L(ctx).Errorf("json.Unmarshal error: %v", err)

		return err
	}
	fmt.Println(token)
	region := "ap-northeast-1"
	creds, err := credentials.NewStaticCredentials(token.AccessKeyId, token.SecretAccessKey, token.SessionToken).Get()
	if err != nil {
		log.L(ctx).Errorf("credentials.NewStaticCredentials error: %v", err)

		return err
	}
	sess, err := session.NewSession(&aws.Config{
		Credentials: credentials.NewStaticCredentialsFromCreds(creds),
		Region:      &region,
	})
	var nonProd []AWSAccount
	orClient := organizations.New(sess)
	var pageToken string
	for {
		input := organizations.ListAccountsInput{}
		if pageToken != "" {
			input = organizations.ListAccountsInput{
				NextToken: &pageToken,
			}
		}
		result, err := orClient.ListAccounts(&input)
		if err != nil {
			log.L(ctx).Errorf("orClient.ListAccounts error: %v", err)

			return err
		}
		for _, account := range result.Accounts {
			if *account.Status != "ACTIVE" {
				continue
			}
			_, err := orClient.DescribeAccount(&organizations.DescribeAccountInput{
				AccountId: account.Id,
			})
			if err != nil {
				log.L(ctx).Errorf("DescribeAccount error: %v", err)

				return err
			}
			nonProd = append(nonProd, AWSAccount{
				AccountID: *account.Id,
				Name:      *account.Name,
			})
		}
		if result.NextToken == nil {
			break
		}
		pageToken = *result.NextToken
	}
	var fields []map[string]interface{}
	for _, account := range nonProd {
		fields = append(fields, map[string]interface{}{
			"名称":      account.Name,
			"account": account.AccountID,
		})
	}

	larkSrv := larkService{
		store: a.store,
	}
	go larkSrv.WriteToBi(ctx, "os", fields)
	log.L(ctx).Infof("write aws to bi success")

	return nil
}

func (a *awsService) ListAccountAssignments(ctx context.Context) {

}
