package azure

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
	"github.com/tidbcloud/observability/pkg/common/utils"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers"
)

type PLSClient struct {
	cli           *armnetwork.PrivateLinkServicesClient
	resourceGroup string
}

var _ providers.PrivateLinkSvcClient = &PLSClient{}

func NewPLSClient(subscription, resourceGroup string, cred azcore.TokenCredential) (*PLSClient, error) {
	factory, err := armnetwork.NewClientFactory(subscription, cred, nil)
	if err != nil {
		return nil, err
	}
	cli := factory.NewPrivateLinkServicesClient()
	return &PLSClient{
		cli:           cli,
		resourceGroup: resourceGroup,
	}, nil
}

func (pls *PLSClient) Get(ctx context.Context, name string) (*armnetwork.PrivateLinkService, error) {
	resp, err := pls.cli.Get(ctx, pls.resourceGroup, name, nil)
	if err != nil {
		return nil, fmt.Errorf("get private link service failed: %w", err)
	}
	return &resp.PrivateLinkService, nil
}

func (pls *PLSClient) AddUserPermissions(ctx context.Context, serviceName string, subscriptions []string) error {
	resp, err := pls.cli.Get(ctx, pls.resourceGroup, serviceName, nil)
	if err != nil {
		return fmt.Errorf("get private link service failed: %w", err)
	}
	if resp.Properties.AutoApproval == nil {
		resp.Properties.AutoApproval = &armnetwork.PrivateLinkServicePropertiesAutoApproval{}
	}
	if resp.Properties.Visibility == nil {
		resp.Properties.Visibility = &armnetwork.PrivateLinkServicePropertiesVisibility{}
	}
	for _, sub := range subscriptions {
		if !utils.ContainsValue(resp.Properties.AutoApproval.Subscriptions, sub) {
			resp.Properties.AutoApproval.Subscriptions = append(resp.Properties.AutoApproval.Subscriptions, to.Ptr(sub))
		}
		if !utils.ContainsValue(resp.Properties.Visibility.Subscriptions, sub) {
			resp.Properties.Visibility.Subscriptions = append(resp.Properties.Visibility.Subscriptions, to.Ptr(sub))
		}
	}

	poller, err := pls.cli.BeginCreateOrUpdate(ctx, pls.resourceGroup, serviceName, resp.PrivateLinkService, nil)
	if err != nil {
		return fmt.Errorf("create or update private link service failed: %w", err)
	}

	_, err = poller.PollUntilDone(ctx, nil)
	return err
}

func (pls *PLSClient) DeleteUserPermissions(ctx context.Context, serviceID string, subs2Remove []string) error {
	resp, err := pls.cli.Get(ctx, pls.resourceGroup, serviceID, nil)
	if err != nil {
		return fmt.Errorf("get private link service failed: %w", err)
	}

	apprSubs, vizSubs := []*string{}, []*string{}
	if resp.Properties.AutoApproval == nil || resp.Properties.Visibility == nil {
		return nil
	}
	for _, sub := range resp.Properties.AutoApproval.Subscriptions {
		if !utils.IsIncludeString(subs2Remove, *sub) {
			apprSubs = append(apprSubs, sub)
		}
		if !utils.IsIncludeString(subs2Remove, *sub) {
			vizSubs = append(vizSubs, sub)
		}
	}
	resp.Properties.AutoApproval.Subscriptions = apprSubs
	resp.Properties.Visibility.Subscriptions = vizSubs

	poller, err := pls.cli.BeginCreateOrUpdate(ctx, pls.resourceGroup, serviceID, resp.PrivateLinkService, nil)
	if err != nil {
		return fmt.Errorf("create or update private link service failed: %w", err)
	}

	_, err = poller.PollUntilDone(ctx, nil)
	return err
}
