package services

import (
	"context"
	"fmt"

	dpmv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/hack/mock-dpm/store"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
)

// BucketService implements the BucketServiceServer interface.
type BucketService struct {
	dpmv1.UnimplementedBucketServiceServer
	store *store.MemoryStore
}

// NewBucketService creates a new BucketService.
func NewBucketService(s *store.MemoryStore) *BucketService {
	return &BucketService{store: s}
}

// CreateBucket creates a new bucket.
func (s *BucketService) CreateBucket(ctx context.Context, req *dpmv1.CreateBucketRequest) (*dpmv1.Bucket, error) {
	if req.DataplaneId == "" {
		return nil, status.Error(codes.InvalidArgument, "dataplane_id is required")
	}
	if req.Bucket == nil {
		return nil, status.Error(codes.InvalidArgument, "bucket is required")
	}

	if existing, ok := s.store.GetBucket(req.DataplaneId, req.Bucket.Id); ok {
		return existing, nil
	}

	bucket := &dpmv1.Bucket{
		Id:     req.Bucket.Id,
		Region: req.Bucket.Region,
		Name:   fmt.Sprintf("mock-bucket-%s-%s", req.DataplaneId, req.Bucket.Id),
		Tags:   req.Bucket.Tags,
		Status: "Ready",
	}

	s.store.SetBucket(req.DataplaneId, bucket)
	return bucket, nil
}

// GetBucket retrieves a bucket by ID.
func (s *BucketService) GetBucket(ctx context.Context, req *dpmv1.GetBucketRequest) (*dpmv1.Bucket, error) {
	if req.DataplaneId == "" || req.BucketId == "" {
		return nil, status.Error(codes.InvalidArgument, "dataplane_id and bucket_id are required")
	}

	bucket, ok := s.store.GetBucket(req.DataplaneId, req.BucketId)
	if !ok {
		return nil, status.Error(codes.NotFound, "bucket not found")
	}

	return bucket, nil
}

// ListBuckets returns all buckets for a dataplane.
func (s *BucketService) ListBuckets(ctx context.Context, req *dpmv1.ListBucketsRequest) (*dpmv1.ListBucketsResponse, error) {
	if req.DataplaneId == "" {
		return nil, status.Error(codes.InvalidArgument, "dataplane_id is required")
	}

	buckets := s.store.ListBuckets(req.DataplaneId)
	return &dpmv1.ListBucketsResponse{
		Buckets: buckets,
	}, nil
}

// DeleteBucket deletes a bucket.
func (s *BucketService) DeleteBucket(ctx context.Context, req *dpmv1.DeleteBucketRequest) (*emptypb.Empty, error) {
	if req.DataplaneId == "" || req.BucketId == "" {
		return nil, status.Error(codes.InvalidArgument, "dataplane_id and bucket_id are required")
	}

	s.store.DeleteBucket(req.DataplaneId, req.BucketId)
	return &emptypb.Empty{}, nil
}

// GrantDataplanePermission grants permission to another dataplane.
func (s *BucketService) GrantDataplanePermission(ctx context.Context, req *dpmv1.GrantDataplanePermissionRequest) (*emptypb.Empty, error) {
	// Mock implementation - just return success
	return &emptypb.Empty{}, nil
}

// RevokeDataplanePermission revokes permission from another dataplane.
func (s *BucketService) RevokeDataplanePermission(ctx context.Context, req *dpmv1.RevokeDataplanePermissionRequest) (*emptypb.Empty, error) {
	// Mock implementation - just return success
	return &emptypb.Empty{}, nil
}

// GetDataplanePermission gets the permission status.
func (s *BucketService) GetDataplanePermission(ctx context.Context, req *dpmv1.GetDataplanePermissionRequest) (*dpmv1.GetDataplanePermissionResponse, error) {
	return &dpmv1.GetDataplanePermissionResponse{
		Status: dpmv1.GetDataplanePermissionResponse_Synced,
	}, nil
}

// ApplyLifecycleRules applies lifecycle rules to a bucket.
func (s *BucketService) ApplyLifecycleRules(ctx context.Context, req *dpmv1.ApplyLifecycleRulesRequest) (*emptypb.Empty, error) {
	// Mock implementation - just return success
	return &emptypb.Empty{}, nil
}

// GetLifecycleRules gets the lifecycle rules for a bucket.
func (s *BucketService) GetLifecycleRules(ctx context.Context, req *dpmv1.GetLifecycleRulesRequest) (*dpmv1.GetLifecycleRulesResponse, error) {
	return &dpmv1.GetLifecycleRulesResponse{
		Status: dpmv1.GetLifecycleRulesResponse_Synced,
		Rules:  []*dpmv1.LifecycleRule{},
	}, nil
}
