package providers

import (
	"bytes"
	"context"
	"io"

	armauthorization "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3"
	armnetwork "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
	"github.com/tidbcloud/observability/pkg/common/message"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers/alicloud"

	computepb "cloud.google.com/go/compute/apiv1/computepb"
	cloudiam "cloud.google.com/go/iam"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi"
	privatelink20200415 "github.com/alibabacloud-go/privatelink-20200415/v5/client"
	ram "github.com/alibabacloud-go/ram-20150501/v2/client"

	ec2api "github.com/aws/aws-sdk-go-v2/service/ec2"
	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
	elbtypes "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
	iamapi "github.com/aws/aws-sdk-go-v2/service/iam"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers/aws"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers/gcp"
	"github.com/tidbcloud/observability/pkg/resourceworker/providers/types"
	gcpiam "google.golang.org/api/iam/v1"
)

type S3Client interface {
	CreateBucket(ctx context.Context, name string) error
	BucketExists(ctx context.Context, name string) (bool, error)
	Get(ctx context.Context, bucketName string, objectName string) (*io.ReadCloser, error)
	Put(ctx context.Context, bucketName string, objectName string, reader *bytes.Reader) error
	// ListObjects returns a list of objects in the bucket with the given prefix.
	ListObjects(ctx context.Context, bucketName string, prefix string, options types.ListOptions) ([]string, error)
	AddLifecycle(ctx context.Context, bucketName string, rule []message.LifecycleRuleParam, unusedRulePrefixes []string) error
	RemoveLifecycle(ctx context.Context, bucketName string, name string) error
	// Delete removes objects from the bucket.
	Delete(ctx context.Context, bucketName string, objectNames ...string) error
}

type EndpointServiceClient interface {
	CreateEndpointService(ctx context.Context, name string, lbarns []string) (*ec2api.CreateVpcEndpointServiceConfigurationOutput, error)
	AddUserPermissions(ctx context.Context, serviceID string, userARNs []string) error
	GetEndpointService(ctx context.Context, serviceID string) (*ec2types.ServiceConfiguration, error)
	DeleteEndpointService(ctx context.Context, serviceID string) error
	DeleteUserPermissions(ctx context.Context, serviceID string, userARNs []string) error
}
type ELBClient interface {
	GetLoadBalancer(ctx context.Context, name string) (*elbtypes.LoadBalancer, error)
}

type IAMClient interface {
	AssumeRole(ctx context.Context, roleArn string) *aws.IAMClient
	CreateRole(ctx context.Context, name string, trustDoc string) error
	GetRole(ctx context.Context, name string) (*iamapi.GetRoleOutput, bool, error)
	ListRolePolicies(ctx context.Context, name string, marker *string) (*iamapi.ListRolePoliciesOutput, error)
	PutRolePolicy(ctx context.Context, name string, policyName string, policyDoc string) error
	DeleteRolePolicy(ctx context.Context, name string, policyName string) error
	DeleteRole(ctx context.Context, name string) error
	UpdateAssumeRolePolicy(ctx context.Context, name string, assumeDocument string) error
}

type IAMClientGCP interface {
	AssumeProject(ctx context.Context, project string) *gcp.IAMClient
	CreateServiceAccount(ctx context.Context, name string) (*gcpiam.ServiceAccount, error)
	DeleteServiceAccount(ctx context.Context, name string) error
	GetServiceAccount(ctx context.Context, name string) (*gcpiam.ServiceAccount, bool, error)
	GetServiceAccountIAM(ctx context.Context, name string) (*gcpiam.Policy, error)
	SetServiceAccountIAM(ctx context.Context, name string, policy *gcpiam.Policy) error
	GetBucketPolicy(ctx context.Context, resourcename string) (*cloudiam.Policy3, bool, error)
	SetBucketPolicy(ctx context.Context, resourcename string, policy *cloudiam.Policy3) error
	DeleteBucketPolicy(ctx context.Context, resourcename string, title string) error
}

type PSCClient interface {
	AssumeProject(ctx context.Context, project string) *gcp.PSCClient
	GetPSCService(ctx context.Context, name string) (*computepb.ServiceAttachment, error)
	SetPSCService(ctx context.Context, name string, setting *computepb.ServiceAttachment) error
	CreatePublishedServicePscEndpoint(ctx context.Context, region, network, subnet, target, name, namespace string, tags map[string]string) error
	DeletePublishedServicePscEndpoint(ctx context.Context, region, name string) error
	GetPublishedServicePscEndpoint(ctx context.Context, region, name string) (*computepb.ForwardingRule, error)
	// checkNamespaceNetworkAssociation checks if a Service Directory namespace is associated with the specified network
	CheckNamespaceNetworkAssociation(ctx context.Context, region, network, namespace string) (bool, error)
}

type PrivateEndpointClient interface {
	AssumeRole(ctx context.Context, roleArn string) *aws.PrivateEndpointClient
	DescribeSubnets(ctx context.Context, subnetIDs []string) (*ec2api.DescribeSubnetsOutput, error)
	DescribeVpcEndpointServices(ctx context.Context, serviceNames []string) (*ec2api.DescribeVpcEndpointServicesOutput, error)
	CreateVpcEndpoint(ctx context.Context, name string, vpcID string, serviceName string, subnetIDs []string, endpointType string, secretGroupIDs []string, tags map[string]string) (*ec2api.CreateVpcEndpointOutput, error)
	DeleteVpcEndpoints(ctx context.Context, endpointIDs []string) (*ec2api.DeleteVpcEndpointsOutput, error)
	DescribeVpcEndpoints(ctx context.Context, endpointIDs []string) (*ec2api.DescribeVpcEndpointsOutput, error)
	DescribeVpcEndpointsByName(ctx context.Context, name string) (*ec2api.DescribeVpcEndpointsOutput, error)
}

// ------ interfaces for azure -----

type PrivateLinkSvcClient interface {
	Get(ctx context.Context, name string) (*armnetwork.PrivateLinkService, error)
	AddUserPermissions(ctx context.Context, serviceName string, userARNs []string) error
	DeleteUserPermissions(ctx context.Context, serviceName string, userARNs []string) error
}

type PLSEndpointClient interface {
	Get(ctx context.Context, name string) (*armnetwork.PrivateEndpoint, error)
	Create(ctx context.Context, name, vnetName, subnetID, serviceName, location string, tags map[string]string) (*armnetwork.PrivateEndpoint, error)
	Delete(ctx context.Context, name string) error
	GetPrivateIP(ctx context.Context, epName string) (*string, error)
}

type IAMClientAzure interface {
	CreateUserIdentity(ctx context.Context, name string) (*armmsi.Identity, error)
	GetUserIdentity(ctx context.Context, name string) (*armmsi.Identity, bool, error)
	DeleteUserIdentity(ctx context.Context, name string) error
	CreateOrUpdateRoleAssignmentForPrincipal(ctx context.Context, storageID string, params *armauthorization.RoleAssignmentProperties) (*armauthorization.RoleAssignment, error)
	CreateOrUpdateRoleAssignment(ctx context.Context, storageID, name string, params *armauthorization.RoleAssignmentProperties) (*armauthorization.RoleAssignment, error)
	GetRoleAssignment(ctx context.Context, storageID, identityName string) (*armauthorization.RoleAssignment, bool, error)
	GetRoleAssignmentByPrincipalID(ctx context.Context, storageID, principalID string) (*armauthorization.RoleAssignment, bool, error)
	DeleteRoleAssignment(ctx context.Context, storageID, identityName string) error
	DeleteRoleAssignmentByPrincipalID(ctx context.Context, storageID, principalID string) error
	CreateOrUpdateFederatedIdentity(ctx context.Context, identityName string, oidcIssuer string, workloadServiceAccounts []string) error
	GetWorkloadIdentity(ctx context.Context, identityName string) (*types.AzureWorkloadIdentity, bool, error)
}

// ------ interfaces for ali cloud -----

type IAMClientAliCloud interface {
	AssumeRole(ctx context.Context, roleArn string) *alicloud.IAMClient
	CreateRole(ctx context.Context, name string, trustDoc string) error
	GetRole(ctx context.Context, name string) (*ram.GetRoleResponse, bool, error)
	ListRolePolicies(ctx context.Context, name string, marker *string) (*ram.ListPoliciesForRoleResponse, error)
	GetCustomPolicyDocument(ctx context.Context, policyName string) (string, bool, error)
	CreateRolePolicy(ctx context.Context, name string, policyName string, policyDoc string) error
	UpdateRolePolicy(ctx context.Context, name string, policyName string, policyDoc string) error
	DeleteRolePolicy(ctx context.Context, name string, policyName string) error
	DeleteRole(ctx context.Context, name string) error
	UpdateAssumeRolePolicy(ctx context.Context, name string, assumeDocument string) error
}

type AliEndpointServiceClient interface {
	GetAliEndpointService(ctx context.Context, serviceID string) (*privatelink20200415.GetVpcEndpointServiceAttributeResponseBody, error)
	AddUserPermissions(ctx context.Context, serviceID string, userARNs []string) error
	DeleteUserPermissions(ctx context.Context, serviceID string, userARNs []string) error
}
