package export

import (
	"context"

	"github.com/tidbcloud/tiinf/sdk/auditlog"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (s *serverImpl) CreateExport(
	ctx context.Context,
	req *openapingv1beta2.CreateExportRequest,
) (*openapingv1beta2.Export, error) {
	ctx, span := tracer.Start(ctx, "CreateExport")
	defer span.End()
	var (
		err       error
		eventType auditlog.EventType
		reqMeta   *metadata.RequestMeta
	)

	detailsFunc := func() auditlog.Details {
		details := eventbus.NewAuditLogDetails(eventbus.TierTypePremium)
		details[auditlog.KeyTargetClusterId] = req.GetTidbId()
		if export := req.GetExport(); export != nil {
			details[auditlog.KeyDisplayName] = export.GetDisplayName()
			details[auditlog.KeyExportID] = export.GetExportId()
			if opts := export.GetExportOptions(); opts != nil {
				details["export_file_type"] = opts.GetFileType().String()
			}
		}
		return details
	}
	defer func() {
		if !req.GetValidateOnly() {
			if eventType != 0 {
				go s.auditLogSender.SubmitAuditLogForNextgen(context.WithoutCancel(ctx), eventType, reqMeta, detailsFunc, err)
			}
		}
	}()

	reqMeta, err = metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	if req.TidbId == "" {
		return nil, bizerr.New(bizerr.ErrCodeParams, "tidb id is required")
	}
	if req.Export == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "export is required")
	}
	eventType = createExportAuditLogEventType(req.Export.GetCloudStorage())
	if eventType == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "unsupported cloud storage type")
	}

	createdBy := common.BuildCreatedBy(reqMeta.Email, reqMeta.ApiPublicKey)
	globalExport := ToGlobalExport(req.Export, createdBy)
	resp, err := s.nextGenCli.CreateExport(ctx, &globalngv1.CreateExportRequest{
		ClusterId:    req.TidbId,
		Export:       globalExport,
		ValidateOnly: req.ValidateOnly,
	})
	if err != nil {
		return nil, err
	}
	return ToOpenAPIExport(resp), nil
}

func createExportAuditLogEventType(storage *openapingv1beta2.CloudStorage) auditlog.EventType {
	switch storage.GetType() {
	case openapingv1beta2.CloudStorageType_S3:
		return auditlog.EventExportDataToAWS
	case openapingv1beta2.CloudStorageType_GCS:
		return auditlog.EventExportDataToGCP
	case openapingv1beta2.CloudStorageType_AZURE_BLOB:
		return auditlog.EventExportDataToAzure
	case openapingv1beta2.CloudStorageType_OSS:
		return auditlog.EventExportDataToAlibabaCloud
	default:
		return 0
	}
}
