package dataflowcli

import (
	"context"

	"braces.dev/errtrace"
	legacyproto "github.com/golang/protobuf/proto"
	"github.com/tidbcloud/dataflow-service/idl/pbgen/proto/dataflow"
	"google.golang.org/grpc"

	dataflowadapter "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/dataflow"
)

type clientImpl struct {
	dataflow.BackupInternalServiceClient

	conn grpc.ClientConnInterface
}

const (
	prepareClassicRestoreAccessMethod = "/dataflow.BackupInternalService/PrepareClassicRestoreAccess"
	cleanupClassicRestoreAccessMethod = "/dataflow.BackupInternalService/CleanupClassicRestoreAccess"
)

// The compatibility messages use the same protobuf field numbers as the
// Dataflow API. gRPC serializes protobuf wire data, so their Go type names do
// not need to match the generated server types.
type prepareClassicRestoreAccessRequestWire struct {
	BackupID       uint64 `protobuf:"varint,1,opt,name=backup_id,json=backupId,proto3"`
	BucketID       uint64 `protobuf:"varint,2,opt,name=bucket_id,json=bucketId,proto3"`
	RestoreID      string `protobuf:"bytes,3,opt,name=restore_id,json=restoreId,proto3"`
	TrustedRoleARN string `protobuf:"bytes,4,opt,name=trusted_role_arn,json=trustedRoleArn,proto3"`
}

func (m *prepareClassicRestoreAccessRequestWire) Reset() {
	*m = prepareClassicRestoreAccessRequestWire{}
}
func (m *prepareClassicRestoreAccessRequestWire) String() string {
	return legacyproto.CompactTextString(m)
}
func (*prepareClassicRestoreAccessRequestWire) ProtoMessage() {}

type prepareClassicRestoreAccessResponseWire struct {
	SourceRoleARN string `protobuf:"bytes,1,opt,name=source_role_arn,json=sourceRoleArn,proto3"`
	ExternalID    string `protobuf:"bytes,2,opt,name=external_id,json=externalId,proto3"`
}

func (m *prepareClassicRestoreAccessResponseWire) Reset() {
	*m = prepareClassicRestoreAccessResponseWire{}
}
func (m *prepareClassicRestoreAccessResponseWire) String() string {
	return legacyproto.CompactTextString(m)
}
func (*prepareClassicRestoreAccessResponseWire) ProtoMessage() {}

type cleanupClassicRestoreAccessRequestWire struct {
	BucketID  uint64 `protobuf:"varint,1,opt,name=bucket_id,json=bucketId,proto3"`
	RestoreID string `protobuf:"bytes,2,opt,name=restore_id,json=restoreId,proto3"`
}

func (m *cleanupClassicRestoreAccessRequestWire) Reset() {
	*m = cleanupClassicRestoreAccessRequestWire{}
}
func (m *cleanupClassicRestoreAccessRequestWire) String() string {
	return legacyproto.CompactTextString(m)
}
func (*cleanupClassicRestoreAccessRequestWire) ProtoMessage() {}

type emptyResponseWire struct{}

func (m *emptyResponseWire) Reset()         { *m = emptyResponseWire{} }
func (m *emptyResponseWire) String() string { return legacyproto.CompactTextString(m) }
func (*emptyResponseWire) ProtoMessage()    {}

func (c clientImpl) GetBackup(ctx context.Context, req *dataflow.GetBackupReq) (*dataflow.GetBackupResp, error) {
	return c.BackupInternalServiceClient.GetBackup(ctx, req)
}

func (c clientImpl) GrantAccessBackupBucket(ctx context.Context, req *dataflow.GrantAccessBackupBucketReq) error {
	_, err := c.BackupInternalServiceClient.GrantAccessBackupBucket(ctx, req)
	if err != nil {
		return errtrace.Wrap(err)
	}
	return nil
}

func (c clientImpl) RevokeAccessBackupBucket(ctx context.Context, req *dataflow.RevokeAccessBackupBucketReq) error {
	_, err := c.BackupInternalServiceClient.RevokeAccessBackupBucket(ctx, req)
	if err != nil {
		return errtrace.Wrap(err)
	}
	return nil
}

func (c clientImpl) PrepareClassicRestoreAccess(
	ctx context.Context,
	req *dataflowadapter.PrepareClassicRestoreAccessRequest,
) (*dataflowadapter.PrepareClassicRestoreAccessResponse, error) {
	wireResp := &prepareClassicRestoreAccessResponseWire{}
	err := c.conn.Invoke(ctx, prepareClassicRestoreAccessMethod, &prepareClassicRestoreAccessRequestWire{
		BackupID: req.BackupID, BucketID: req.BucketID, RestoreID: req.RestoreID, TrustedRoleARN: req.TrustedRoleARN,
	}, wireResp)
	if err != nil {
		return nil, errtrace.Wrap(err)
	}
	return &dataflowadapter.PrepareClassicRestoreAccessResponse{
		SourceRoleARN: wireResp.SourceRoleARN,
		ExternalID:    wireResp.ExternalID,
	}, nil
}

func (c clientImpl) CleanupClassicRestoreAccess(ctx context.Context, req *dataflowadapter.CleanupClassicRestoreAccessRequest) error {
	err := c.conn.Invoke(ctx, cleanupClassicRestoreAccessMethod, &cleanupClassicRestoreAccessRequestWire{
		BucketID: req.BucketID, RestoreID: req.RestoreID,
	}, &emptyResponseWire{})
	return errtrace.Wrap(err)
}
